1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
4 * Copyright (C) James Liggett 2010 <jrliggett@cox.net>
6 * anjuta is free software: you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * anjuta is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14 * See the GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License along
17 * with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include "git-log-data-command.h"
22 #define COMMIT_REGEX "^commit ([[:xdigit:]]{40})"
23 #define PARENT_REGEX "^parents (.*)"
24 #define AUTHOR_REGEX "^author (.*)"
25 #define TIME_REGEX "^time (\\d*)"
26 #define SHORT_LOG_REGEX "^(?:short log) (.*)"
28 struct _GitLogDataCommandPriv
30 GAsyncQueue
*input_queue
;
32 GHashTable
*revisions
;
33 GitRevision
*current_revision
;
38 GRegex
*short_log_regex
;
41 G_DEFINE_TYPE (GitLogDataCommand
, git_log_data_command
,
42 ANJUTA_TYPE_ASYNC_COMMAND
);
45 git_log_data_command_init (GitLogDataCommand
*self
)
47 self
->priv
= g_new0 (GitLogDataCommandPriv
, 1);
48 self
->priv
->input_queue
= g_async_queue_new_full (g_free
);
49 self
->priv
->output_queue
= g_queue_new ();
50 self
->priv
->revisions
= g_hash_table_new_full (g_str_hash
, g_str_equal
,
51 g_free
, g_object_unref
);
52 self
->priv
->commit_regex
= g_regex_new (COMMIT_REGEX
, 0, 0, NULL
);
53 self
->priv
->parent_regex
= g_regex_new (PARENT_REGEX
, 0, 0, NULL
);
54 self
->priv
->author_regex
= g_regex_new (AUTHOR_REGEX
, 0, 0, NULL
);
55 self
->priv
->time_regex
= g_regex_new (TIME_REGEX
, 0, 0, NULL
);
56 self
->priv
->short_log_regex
= g_regex_new (SHORT_LOG_REGEX
, 0, 0, NULL
);
60 git_log_data_command_finalize (GObject
*object
)
62 GitLogDataCommand
*self
;
63 GList
*current_output
;
65 self
= GIT_LOG_DATA_COMMAND (object
);
67 g_async_queue_unref (self
->priv
->input_queue
);
68 current_output
= self
->priv
->output_queue
->head
;
70 while (current_output
)
72 g_object_unref (current_output
->data
);
73 current_output
= g_list_next (current_output
);
76 g_queue_free (self
->priv
->output_queue
);
77 g_hash_table_destroy (self
->priv
->revisions
);
78 g_regex_unref (self
->priv
->commit_regex
);
79 g_regex_unref (self
->priv
->parent_regex
);
80 g_regex_unref (self
->priv
->author_regex
);
81 g_regex_unref (self
->priv
->time_regex
);
82 g_regex_unref (self
->priv
->short_log_regex
);
84 G_OBJECT_CLASS (git_log_data_command_parent_class
)->finalize (object
);
88 git_log_data_command_run (AnjutaCommand
*command
)
90 GitLogDataCommand
*self
;
92 GMatchInfo
*commit_match_info
;
93 GMatchInfo
*parent_match_info
;
94 GMatchInfo
*author_match_info
;
95 GMatchInfo
*time_match_info
;
96 GMatchInfo
*short_log_match_info
;
101 GitRevision
*parent_revision
;
106 self
= GIT_LOG_DATA_COMMAND (command
);
108 while ((line
= g_async_queue_pop (self
->priv
->input_queue
)))
110 /* An empty string means there's nothing left to process */
111 if (g_utf8_strlen (line
, -1) == 0)
117 commit_match_info
= NULL
;
118 parent_match_info
= NULL
;
119 author_match_info
= NULL
;
120 time_match_info
= NULL
;
121 short_log_match_info
= NULL
;
123 /* Entries are delimited by the hex value 0x0c */
124 if (*line
== 0x0c && self
->priv
->current_revision
)
126 anjuta_async_command_lock (ANJUTA_ASYNC_COMMAND (command
));
127 g_queue_push_tail (self
->priv
->output_queue
,
128 self
->priv
->current_revision
);
129 anjuta_async_command_unlock (ANJUTA_ASYNC_COMMAND (command
));
131 anjuta_command_notify_data_arrived (command
);
134 if (g_regex_match (self
->priv
->commit_regex
, line
, 0, &commit_match_info
))
136 commit_sha
= g_match_info_fetch (commit_match_info
, 1);
138 self
->priv
->current_revision
= g_hash_table_lookup (self
->priv
->revisions
,
141 if (!self
->priv
->current_revision
)
143 self
->priv
->current_revision
= git_revision_new ();
144 git_revision_set_sha (self
->priv
->current_revision
, commit_sha
);
145 g_hash_table_insert (self
->priv
->revisions
, g_strdup (commit_sha
),
146 g_object_ref (self
->priv
->current_revision
));
151 else if (g_regex_match (self
->priv
->parent_regex
, line
, 0,
154 parents
= g_match_info_fetch (parent_match_info
, 1);
155 parent_shas
= g_strsplit (parents
, " ", -1);
157 for (i
= 0; parent_shas
[i
]; i
++)
159 parent_revision
= g_hash_table_lookup (self
->priv
->revisions
,
162 if (!parent_revision
)
164 parent_revision
= git_revision_new ();
165 git_revision_set_sha (parent_revision
, parent_shas
[i
]);
166 g_hash_table_insert (self
->priv
->revisions
,
167 g_strdup (parent_shas
[i
]),
168 g_object_ref (parent_revision
));
171 git_revision_add_child (parent_revision
,
172 self
->priv
->current_revision
);
176 g_strfreev (parent_shas
);
178 else if (g_regex_match (self
->priv
->author_regex
, line
, 0,
181 author
= g_match_info_fetch (author_match_info
, 1);
182 git_revision_set_author (self
->priv
->current_revision
, author
);
186 else if (g_regex_match (self
->priv
->time_regex
, line
, 0,
189 time
= g_match_info_fetch (time_match_info
, 1);
190 git_revision_set_date (self
->priv
->current_revision
, atol (time
));
194 else if (g_regex_match (self
->priv
->short_log_regex
, line
, 0,
195 &short_log_match_info
))
197 short_log
= g_match_info_fetch (short_log_match_info
, 1);
198 git_revision_set_short_log (self
->priv
->current_revision
, short_log
);
203 if (commit_match_info
)
204 g_match_info_free (commit_match_info
);
206 if (parent_match_info
)
207 g_match_info_free (parent_match_info
);
209 if (author_match_info
)
210 g_match_info_free (author_match_info
);
213 g_match_info_free (time_match_info
);
215 if (short_log_match_info
)
216 g_match_info_free (short_log_match_info
);
225 git_log_data_command_class_init (GitLogDataCommandClass
*klass
)
227 GObjectClass
* object_class
= G_OBJECT_CLASS (klass
);
228 AnjutaCommandClass
*command_class
= ANJUTA_COMMAND_CLASS (klass
);
230 object_class
->finalize
= git_log_data_command_finalize
;
231 command_class
->run
= git_log_data_command_run
;
235 git_log_data_command_new (void)
237 return g_object_new (GIT_TYPE_LOG_DATA_COMMAND
, NULL
);
241 git_log_data_command_get_output (GitLogDataCommand
*self
)
243 return self
->priv
->output_queue
;
247 git_log_data_command_push_line (GitLogDataCommand
*self
, const gchar
*line
)
249 g_async_queue_push (self
->priv
->input_queue
, g_strdup (line
));