[anjuta] git: Process log data asynchronously
- From: James Liggett <jrliggett src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [anjuta] git: Process log data asynchronously
- Date: Tue, 14 Dec 2010 09:31:58 +0000 (UTC)
commit 0681b47521b7b1ff84f560201f521a52fd1c533a
Author: James Liggett <jrliggett cox net>
Date: Tue Dec 14 01:28:41 2010 -0800
git: Process log data asynchronously
plugins/git/Makefile.am | 5 +-
plugins/git/git-log-command.c | 199 +++++++---------------------
plugins/git/git-log-command.h | 1 +
plugins/git/git-log-data-command.c | 250 ++++++++++++++++++++++++++++++++++++
plugins/git/git-log-data-command.h | 61 +++++++++
5 files changed, 365 insertions(+), 151 deletions(-)
---
diff --git a/plugins/git/Makefile.am b/plugins/git/Makefile.am
index d986b52..46aa34f 100644
--- a/plugins/git/Makefile.am
+++ b/plugins/git/Makefile.am
@@ -217,7 +217,10 @@ libanjuta_git_la_SOURCES = \
git-rebase-pane.c \
git-rebase-pane.h \
git-log-pane.c \
- git-log-pane.h
+ git-log-pane.h \
+ git-log-data-command.c \
+ git-log-data-command.h
+
libanjuta_git_la_LDFLAGS = $(ANJUTA_PLUGIN_LDFLAGS)
diff --git a/plugins/git/git-log-command.c b/plugins/git/git-log-command.c
index a63526e..c937940 100644
--- a/plugins/git/git-log-command.c
+++ b/plugins/git/git-log-command.c
@@ -22,24 +22,13 @@
* Boston, MA 02110-1301, USA.
*/
-#define COMMIT_REGEX "^commit ([[:xdigit:]]{40})"
-#define PARENT_REGEX "^parents (.*)"
-#define AUTHOR_REGEX "^author (.*)"
-#define TIME_REGEX "^time (\\d*)"
-#define SHORT_LOG_REGEX "^(?:short log) (.*)"
-
#include "git-log-command.h"
struct _GitLogCommandPriv
{
- GQueue *output_queue;
- GHashTable *revisions;
- GitRevision *current_revision;
- GRegex *commit_regex;
- GRegex *parent_regex;
- GRegex *author_regex;
- GRegex *time_regex;
- GRegex *short_log_regex;
+ GitLogDataCommand *data_command;
+ guint return_code;
+
gchar *branch;
gchar *path;
@@ -55,44 +44,43 @@ struct _GitLogCommandPriv
G_DEFINE_TYPE (GitLogCommand, git_log_command, GIT_TYPE_COMMAND);
static void
+on_data_command_data_arrived (AnjutaCommand *command, GitLogCommand *self)
+{
+ anjuta_command_notify_data_arrived (command);
+}
+
+static void
+on_data_command_finished (AnjutaCommand *command, guint return_code,
+ GitLogCommand *self)
+{
+ ANJUTA_COMMAND_CLASS (git_log_command_parent_class)->notify_complete (ANJUTA_COMMAND (self),
+ self->priv->return_code);
+}
+
+static void
git_log_command_init (GitLogCommand *self)
{
self->priv = g_new0 (GitLogCommandPriv, 1);
- self->priv->output_queue = g_queue_new ();
- self->priv->revisions = g_hash_table_new_full (g_str_hash, g_str_equal,
- g_free, g_object_unref);
- self->priv->commit_regex = g_regex_new (COMMIT_REGEX, 0, 0, NULL);
- self->priv->parent_regex = g_regex_new (PARENT_REGEX, 0, 0, NULL);
- self->priv->author_regex = g_regex_new (AUTHOR_REGEX, 0, 0, NULL);
- self->priv->time_regex = g_regex_new (TIME_REGEX, 0, 0, NULL);
- self->priv->short_log_regex = g_regex_new (SHORT_LOG_REGEX, 0, 0, NULL);
+
+ self->priv->data_command = git_log_data_command_new ();
+
+ g_signal_connect (G_OBJECT (self->priv->data_command), "data-arrived",
+ G_CALLBACK (on_data_command_data_arrived),
+ self);
+
+ g_signal_connect (G_OBJECT (self->priv->data_command), "command-finished",
+ G_CALLBACK (on_data_command_finished),
+ self);
}
static void
git_log_command_finalize (GObject *object)
{
GitLogCommand *self;
- GList *current_output;
self = GIT_LOG_COMMAND (object);
- current_output = self->priv->output_queue->head;
-
- while (current_output)
- {
- g_object_unref (current_output->data);
- current_output = g_list_next (current_output);
- }
-
- g_queue_free (self->priv->output_queue);
- g_hash_table_destroy (self->priv->revisions);
- g_regex_unref (self->priv->commit_regex);
- g_regex_unref (self->priv->parent_regex);
- g_regex_unref (self->priv->author_regex);
- g_regex_unref (self->priv->time_regex);
- g_regex_unref (self->priv->short_log_regex);
- g_free (self->priv->branch);
- g_free (self->priv->path);
+ g_object_unref (self->priv->data_command);
g_free (self->priv->author);
g_free (self->priv->grep);
g_free (self->priv->since_date);
@@ -177,127 +165,37 @@ git_log_command_run (AnjutaCommand *command)
git_command_add_arg (GIT_COMMAND (command), "--");
git_command_add_arg (GIT_COMMAND (command), self->priv->path);
}
+
+ /* Start the data processing task */
+ anjuta_command_start (ANJUTA_COMMAND (self->priv->data_command));
return 0;
}
static void
-git_log_command_handle_output (GitCommand *git_command, const gchar *output)
+git_log_command_notify_complete (AnjutaCommand *command, guint return_code)
{
GitLogCommand *self;
- GMatchInfo *commit_match_info;
- GMatchInfo *parent_match_info;
- GMatchInfo *author_match_info;
- GMatchInfo *time_match_info;
- GMatchInfo *short_log_match_info;
- gchar *commit_sha;
- gchar *parents;
- gchar **parent_shas;
- gint i;
- GitRevision *parent_revision;
- gchar *author;
- gchar *time;
- gchar *short_log;
-
- self = GIT_LOG_COMMAND (git_command);
- commit_match_info = NULL;
- parent_match_info = NULL;
- author_match_info = NULL;
- time_match_info = NULL;
- short_log_match_info = NULL;
-
- /* Entries are delimited by the hex value 0x0c */
- if (*output == 0x0c && self->priv->current_revision)
- {
- g_queue_push_tail (self->priv->output_queue,
- self->priv->current_revision);
- anjuta_command_notify_data_arrived (ANJUTA_COMMAND (git_command));
- }
-
- if (g_regex_match (self->priv->commit_regex, output, 0, &commit_match_info))
- {
- commit_sha = g_match_info_fetch (commit_match_info, 1);
-
- self->priv->current_revision = g_hash_table_lookup (self->priv->revisions,
- commit_sha);
-
- if (!self->priv->current_revision)
- {
- self->priv->current_revision = git_revision_new ();
- git_revision_set_sha (self->priv->current_revision, commit_sha);
- g_hash_table_insert (self->priv->revisions, g_strdup (commit_sha),
- g_object_ref (self->priv->current_revision));
- }
-
- g_free (commit_sha);
- }
- else if (g_regex_match (self->priv->parent_regex, output, 0,
- &parent_match_info))
- {
- parents = g_match_info_fetch (parent_match_info, 1);
- parent_shas = g_strsplit (parents, " ", -1);
-
- for (i = 0; parent_shas[i]; i++)
- {
- parent_revision = g_hash_table_lookup (self->priv->revisions,
- parent_shas[i]);
-
- if (!parent_revision)
- {
- parent_revision = git_revision_new ();
- git_revision_set_sha (parent_revision, parent_shas[i]);
- g_hash_table_insert (self->priv->revisions,
- g_strdup (parent_shas[i]),
- g_object_ref (parent_revision));
- }
-
- git_revision_add_child (parent_revision,
- self->priv->current_revision);
- }
-
- g_free (parents);
- g_strfreev (parent_shas);
- }
- else if (g_regex_match (self->priv->author_regex, output, 0,
- &author_match_info))
- {
- author = g_match_info_fetch (author_match_info, 1);
- git_revision_set_author (self->priv->current_revision, author);
-
- g_free (author);
- }
- else if (g_regex_match (self->priv->time_regex, output, 0,
- &time_match_info))
- {
- time = g_match_info_fetch (time_match_info, 1);
- git_revision_set_date (self->priv->current_revision, atol (time));
-
- g_free (time);
- }
- else if (g_regex_match (self->priv->short_log_regex, output, 0,
- &short_log_match_info))
- {
- short_log = g_match_info_fetch (short_log_match_info, 1);
- git_revision_set_short_log (self->priv->current_revision, short_log);
-
- g_free (short_log);
- }
-
- if (commit_match_info)
- g_match_info_free (commit_match_info);
+ self = GIT_LOG_COMMAND (command);
- if (parent_match_info)
- g_match_info_free (parent_match_info);
+ /* Send an empty string to the data processing command so that it knows
+ * to stop when it's done processing data. The command will finish when
+ * the processing thread finishes, and not when git stops executing */
+ git_log_data_command_push_line (self->priv->data_command, "");
- if (author_match_info)
- g_match_info_free (author_match_info);
+ /* Use the git return code */
+ self->priv->return_code = return_code;
+}
- if (time_match_info)
- g_match_info_free (time_match_info);
+static void
+git_log_command_handle_output (GitCommand *git_command, const gchar *output)
+{
+ GitLogCommand *self;
+
+ self = GIT_LOG_COMMAND (git_command);
- if (short_log_match_info)
- g_match_info_free (short_log_match_info);
+ git_log_data_command_push_line (self->priv->data_command, output);
}
static void
@@ -310,6 +208,7 @@ git_log_command_class_init (GitLogCommandClass *klass)
object_class->finalize = git_log_command_finalize;
parent_class->output_handler = git_log_command_handle_output;
command_class->run = git_log_command_run;
+ command_class->notify_complete = git_log_command_notify_complete;
}
@@ -343,5 +242,5 @@ git_log_command_new (const gchar *working_directory,
GQueue *
git_log_command_get_output_queue (GitLogCommand *self)
{
- return self->priv->output_queue;
+ return git_log_data_command_get_output (self->priv->data_command);
}
diff --git a/plugins/git/git-log-command.h b/plugins/git/git-log-command.h
index 5d80600..a708d71 100644
--- a/plugins/git/git-log-command.h
+++ b/plugins/git/git-log-command.h
@@ -28,6 +28,7 @@
#include <glib-object.h>
#include <stdlib.h>
#include "git-command.h"
+#include "git-log-data-command.h"
#include "git-revision.h"
G_BEGIN_DECLS
diff --git a/plugins/git/git-log-data-command.c b/plugins/git/git-log-data-command.c
new file mode 100644
index 0000000..e9821c6
--- /dev/null
+++ b/plugins/git/git-log-data-command.c
@@ -0,0 +1,250 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
+/*
+ * anjuta
+ * Copyright (C) James Liggett 2010 <jrliggett cox net>
+ *
+ * anjuta is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * anjuta is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "git-log-data-command.h"
+
+#define COMMIT_REGEX "^commit ([[:xdigit:]]{40})"
+#define PARENT_REGEX "^parents (.*)"
+#define AUTHOR_REGEX "^author (.*)"
+#define TIME_REGEX "^time (\\d*)"
+#define SHORT_LOG_REGEX "^(?:short log) (.*)"
+
+struct _GitLogDataCommandPriv
+{
+ GAsyncQueue *input_queue;
+ GQueue *output_queue;
+ GHashTable *revisions;
+ GitRevision *current_revision;
+ GRegex *commit_regex;
+ GRegex *parent_regex;
+ GRegex *author_regex;
+ GRegex *time_regex;
+ GRegex *short_log_regex;
+};
+
+G_DEFINE_TYPE (GitLogDataCommand, git_log_data_command,
+ ANJUTA_TYPE_ASYNC_COMMAND);
+
+static void
+git_log_data_command_init (GitLogDataCommand *self)
+{
+ self->priv = g_new0 (GitLogDataCommandPriv, 1);
+ self->priv->input_queue = g_async_queue_new_full (g_free);
+ self->priv->output_queue = g_queue_new ();
+ self->priv->revisions = g_hash_table_new_full (g_str_hash, g_str_equal,
+ g_free, g_object_unref);
+ self->priv->commit_regex = g_regex_new (COMMIT_REGEX, 0, 0, NULL);
+ self->priv->parent_regex = g_regex_new (PARENT_REGEX, 0, 0, NULL);
+ self->priv->author_regex = g_regex_new (AUTHOR_REGEX, 0, 0, NULL);
+ self->priv->time_regex = g_regex_new (TIME_REGEX, 0, 0, NULL);
+ self->priv->short_log_regex = g_regex_new (SHORT_LOG_REGEX, 0, 0, NULL);
+}
+
+static void
+git_log_data_command_finalize (GObject *object)
+{
+ GitLogDataCommand *self;
+ GList *current_output;
+
+ self = GIT_LOG_DATA_COMMAND (object);
+
+ g_async_queue_unref (self->priv->input_queue);
+ current_output = self->priv->output_queue->head;
+
+ while (current_output)
+ {
+ g_object_unref (current_output->data);
+ current_output = g_list_next (current_output);
+ }
+
+ g_queue_free (self->priv->output_queue);
+ g_hash_table_destroy (self->priv->revisions);
+ g_regex_unref (self->priv->commit_regex);
+ g_regex_unref (self->priv->parent_regex);
+ g_regex_unref (self->priv->author_regex);
+ g_regex_unref (self->priv->time_regex);
+ g_regex_unref (self->priv->short_log_regex);
+
+ G_OBJECT_CLASS (git_log_data_command_parent_class)->finalize (object);
+}
+
+static guint
+git_log_data_command_run (AnjutaCommand *command)
+{
+ GitLogDataCommand *self;
+ gchar *line;
+ GMatchInfo *commit_match_info;
+ GMatchInfo *parent_match_info;
+ GMatchInfo *author_match_info;
+ GMatchInfo *time_match_info;
+ GMatchInfo *short_log_match_info;
+ gchar *commit_sha;
+ gchar *parents;
+ gchar **parent_shas;
+ gint i;
+ GitRevision *parent_revision;
+ gchar *author;
+ gchar *time;
+ gchar *short_log;
+
+ self = GIT_LOG_DATA_COMMAND (command);
+
+ while ((line = g_async_queue_pop (self->priv->input_queue)))
+ {
+ /* An empty string means there's nothing left to process */
+ if (g_utf8_strlen (line, -1) == 0)
+ {
+ g_free (line);
+ break;
+ }
+
+ commit_match_info = NULL;
+ parent_match_info = NULL;
+ author_match_info = NULL;
+ time_match_info = NULL;
+ short_log_match_info = NULL;
+
+ /* Entries are delimited by the hex value 0x0c */
+ if (*line == 0x0c && self->priv->current_revision)
+ {
+ anjuta_async_command_lock (ANJUTA_ASYNC_COMMAND (command));
+ g_queue_push_tail (self->priv->output_queue,
+ self->priv->current_revision);
+ anjuta_async_command_unlock (ANJUTA_ASYNC_COMMAND (command));
+
+ anjuta_command_notify_data_arrived (command);
+ }
+
+ if (g_regex_match (self->priv->commit_regex, line, 0, &commit_match_info))
+ {
+ commit_sha = g_match_info_fetch (commit_match_info, 1);
+
+ self->priv->current_revision = g_hash_table_lookup (self->priv->revisions,
+ commit_sha);
+
+ if (!self->priv->current_revision)
+ {
+ self->priv->current_revision = git_revision_new ();
+ git_revision_set_sha (self->priv->current_revision, commit_sha);
+ g_hash_table_insert (self->priv->revisions, g_strdup (commit_sha),
+ g_object_ref (self->priv->current_revision));
+ }
+
+ g_free (commit_sha);
+ }
+ else if (g_regex_match (self->priv->parent_regex, line, 0,
+ &parent_match_info))
+ {
+ parents = g_match_info_fetch (parent_match_info, 1);
+ parent_shas = g_strsplit (parents, " ", -1);
+
+ for (i = 0; parent_shas[i]; i++)
+ {
+ parent_revision = g_hash_table_lookup (self->priv->revisions,
+ parent_shas[i]);
+
+ if (!parent_revision)
+ {
+ parent_revision = git_revision_new ();
+ git_revision_set_sha (parent_revision, parent_shas[i]);
+ g_hash_table_insert (self->priv->revisions,
+ g_strdup (parent_shas[i]),
+ g_object_ref (parent_revision));
+ }
+
+ git_revision_add_child (parent_revision,
+ self->priv->current_revision);
+ }
+
+ g_free (parents);
+ g_strfreev (parent_shas);
+ }
+ else if (g_regex_match (self->priv->author_regex, line, 0,
+ &author_match_info))
+ {
+ author = g_match_info_fetch (author_match_info, 1);
+ git_revision_set_author (self->priv->current_revision, author);
+
+ g_free (author);
+ }
+ else if (g_regex_match (self->priv->time_regex, line, 0,
+ &time_match_info))
+ {
+ time = g_match_info_fetch (time_match_info, 1);
+ git_revision_set_date (self->priv->current_revision, atol (time));
+
+ g_free (time);
+ }
+ else if (g_regex_match (self->priv->short_log_regex, line, 0,
+ &short_log_match_info))
+ {
+ short_log = g_match_info_fetch (short_log_match_info, 1);
+ git_revision_set_short_log (self->priv->current_revision, short_log);
+
+ g_free (short_log);
+ }
+
+ if (commit_match_info)
+ g_match_info_free (commit_match_info);
+
+ if (parent_match_info)
+ g_match_info_free (parent_match_info);
+
+ if (author_match_info)
+ g_match_info_free (author_match_info);
+
+ if (time_match_info)
+ g_match_info_free (time_match_info);
+
+ if (short_log_match_info)
+ g_match_info_free (short_log_match_info);
+
+ g_free (line);
+ }
+
+ return 0;
+}
+
+static void
+git_log_data_command_class_init (GitLogDataCommandClass *klass)
+{
+ GObjectClass* object_class = G_OBJECT_CLASS (klass);
+ AnjutaCommandClass *command_class = ANJUTA_COMMAND_CLASS (klass);
+
+ object_class->finalize = git_log_data_command_finalize;
+ command_class->run = git_log_data_command_run;
+}
+
+GitLogDataCommand *
+git_log_data_command_new (void)
+{
+ return g_object_new (GIT_TYPE_LOG_DATA_COMMAND, NULL);
+}
+
+GQueue *
+git_log_data_command_get_output (GitLogDataCommand *self)
+{
+ return self->priv->output_queue;
+}
+
+void
+git_log_data_command_push_line (GitLogDataCommand *self, const gchar *line)
+{
+ g_async_queue_push (self->priv->input_queue, g_strdup (line));
+}
diff --git a/plugins/git/git-log-data-command.h b/plugins/git/git-log-data-command.h
new file mode 100644
index 0000000..f7f73e5
--- /dev/null
+++ b/plugins/git/git-log-data-command.h
@@ -0,0 +1,61 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
+/*
+ * anjuta
+ * Copyright (C) James Liggett 2010 <jrliggett cox net>
+ *
+ * anjuta is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * anjuta is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _GIT_LOG_DATA_COMMAND_H_
+#define _GIT_LOG_DATA_COMMAND_H_
+
+#include <glib-object.h>
+#include <stdlib.h>
+#include <libanjuta/anjuta-async-command.h>
+#include "git-revision.h"
+
+G_BEGIN_DECLS
+
+#define GIT_TYPE_LOG_DATA_COMMAND (git_log_data_command_get_type ())
+#define GIT_LOG_DATA_COMMAND(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIT_TYPE_LOG_DATA_COMMAND, GitLogDataCommand))
+#define GIT_LOG_DATA_COMMAND_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIT_TYPE_LOG_DATA_COMMAND, GitLogDataCommandClass))
+#define GIT_IS_LOG_DATA_COMMAND(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIT_TYPE_LOG_DATA_COMMAND))
+#define GIT_IS_LOG_DATA_COMMAND_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIT_TYPE_LOG_DATA_COMMAND))
+#define GIT_LOG_DATA_COMMAND_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIT_TYPE_LOG_DATA_COMMAND, GitLogDataCommandClass))
+
+typedef struct _GitLogDataCommandClass GitLogDataCommandClass;
+typedef struct _GitLogDataCommand GitLogDataCommand;
+typedef struct _GitLogDataCommandPriv GitLogDataCommandPriv;
+
+struct _GitLogDataCommandClass
+{
+ AnjutaAsyncCommandClass parent_class;
+};
+
+struct _GitLogDataCommand
+{
+ AnjutaAsyncCommand parent_instance;
+
+ GitLogDataCommandPriv *priv;
+};
+
+GType git_log_data_command_get_type (void) G_GNUC_CONST;
+GitLogDataCommand *git_log_data_command_new (void);
+GQueue *git_log_data_command_get_output (GitLogDataCommand *self);
+void git_log_data_command_push_line (GitLogDataCommand *self,
+ const gchar *line);
+
+G_END_DECLS
+
+#endif /* _GIT_LOG_DATA_COMMAND_H_ */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]