1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
4 * Copyright (C) James Liggett 2008 <jrliggett@cox.net>
6 * git-command-test is free software.
8 * You may redistribute it and/or modify it under the terms of the
9 * GNU General Public License, as published by the Free Software
10 * Foundation; either version 2 of the License, or (at your option)
13 * git-command-test is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16 * See the GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with git-command-test. If not, write to:
20 * The Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor
22 * Boston, MA 02110-1301, USA.
25 #define COMMIT_REGEX "^commit ([[:xdigit:]]{40})"
26 #define PARENT_REGEX "^parents (.*)"
27 #define AUTHOR_REGEX "^author (.*)"
28 #define TIME_REGEX "^time (\\d*)"
29 #define SHORT_LOG_REGEX "^(?:short log) (.*)"
31 #include "git-log-command.h"
33 struct _GitLogCommandPriv
36 GHashTable
*revisions
;
37 GitRevision
*current_revision
;
42 GRegex
*short_log_regex
;
53 G_DEFINE_TYPE (GitLogCommand
, git_log_command
, GIT_TYPE_COMMAND
);
56 git_log_command_init (GitLogCommand
*self
)
58 self
->priv
= g_new0 (GitLogCommandPriv
, 1);
59 self
->priv
->output_queue
= g_queue_new ();
60 self
->priv
->revisions
= g_hash_table_new_full (g_str_hash
, g_str_equal
,
61 g_free
, g_object_unref
);
62 self
->priv
->commit_regex
= g_regex_new (COMMIT_REGEX
, 0, 0, NULL
);
63 self
->priv
->parent_regex
= g_regex_new (PARENT_REGEX
, 0, 0, NULL
);
64 self
->priv
->author_regex
= g_regex_new (AUTHOR_REGEX
, 0, 0, NULL
);
65 self
->priv
->time_regex
= g_regex_new (TIME_REGEX
, 0, 0, NULL
);
66 self
->priv
->short_log_regex
= g_regex_new (SHORT_LOG_REGEX
, 0, 0, NULL
);
70 git_log_command_finalize (GObject
*object
)
73 GList
*current_output
;
75 self
= GIT_LOG_COMMAND (object
);
76 current_output
= self
->priv
->output_queue
->head
;
78 while (current_output
)
80 g_object_unref (current_output
->data
);
81 current_output
= g_list_next (current_output
);
84 g_queue_free (self
->priv
->output_queue
);
85 g_hash_table_destroy (self
->priv
->revisions
);
86 g_regex_unref (self
->priv
->commit_regex
);
87 g_regex_unref (self
->priv
->parent_regex
);
88 g_regex_unref (self
->priv
->author_regex
);
89 g_regex_unref (self
->priv
->time_regex
);
90 g_regex_unref (self
->priv
->short_log_regex
);
92 g_free (self
->priv
->author
);
93 g_free (self
->priv
->grep
);
94 g_free (self
->priv
->since_date
);
95 g_free (self
->priv
->until_date
);
96 g_free (self
->priv
->since_commit
);
97 g_free (self
->priv
->until_commit
);
100 G_OBJECT_CLASS (git_log_command_parent_class
)->finalize (object
);
104 git_log_command_run (AnjutaCommand
*command
)
108 GString
*commit_range
;
110 self
= GIT_LOG_COMMAND (command
);
112 git_command_add_arg (GIT_COMMAND (command
), "rev-list");
113 git_command_add_arg (GIT_COMMAND (command
), "--topo-order");
114 git_command_add_arg (GIT_COMMAND (command
), "--pretty=format:parents %P%n"
120 if (self
->priv
->author
)
122 filter_arg
= g_strdup_printf ("--author=%s", self
->priv
->author
);
123 git_command_add_arg (GIT_COMMAND (command
), filter_arg
);
127 if (self
->priv
->grep
)
129 filter_arg
= g_strdup_printf ("--grep=%s", self
->priv
->grep
);
130 git_command_add_arg (GIT_COMMAND (command
), filter_arg
);
134 if (self
->priv
->since_date
)
136 filter_arg
= g_strdup_printf ("--since=%s", self
->priv
->since_date
);
137 git_command_add_arg (GIT_COMMAND (command
), filter_arg
);
141 if (self
->priv
->until_date
)
143 filter_arg
= g_strdup_printf ("--until=%s", self
->priv
->until_date
);
144 git_command_add_arg (GIT_COMMAND (command
), filter_arg
);
148 if (self
->priv
->since_commit
|| self
->priv
->until_commit
)
150 commit_range
= g_string_new ("");
152 /* Not the most elegant way of doing it... */
153 if (self
->priv
->since_commit
)
154 g_string_append (commit_range
, self
->priv
->since_commit
);
156 g_string_append (commit_range
, "..");
158 if (self
->priv
->until_commit
)
159 g_string_append (commit_range
, self
->priv
->until_commit
);
161 git_command_add_arg (GIT_COMMAND (command
), commit_range
->str
);
163 g_string_free (commit_range
, TRUE
);
166 git_command_add_arg (GIT_COMMAND (command
), "HEAD");
172 git_log_command_handle_output (GitCommand
*git_command
, const gchar
*output
)
175 GMatchInfo
*match_info
;
180 GitRevision
*parent_revision
;
185 self
= GIT_LOG_COMMAND (git_command
);
187 /* Entries are delimited by the hex value 0x0c */
188 if (*output
== 0x0c && self
->priv
->current_revision
)
190 g_queue_push_tail (self
->priv
->output_queue
,
191 self
->priv
->current_revision
);
192 anjuta_command_notify_data_arrived (ANJUTA_COMMAND (git_command
));
195 if (g_regex_match (self
->priv
->commit_regex
, output
, 0, &match_info
))
197 commit_sha
= g_match_info_fetch (match_info
, 1);
199 self
->priv
->current_revision
= g_hash_table_lookup (self
->priv
->revisions
,
202 if (!self
->priv
->current_revision
)
204 self
->priv
->current_revision
= git_revision_new ();
205 git_revision_set_sha (self
->priv
->current_revision
, commit_sha
);
206 g_hash_table_insert (self
->priv
->revisions
, g_strdup (commit_sha
),
207 g_object_ref (self
->priv
->current_revision
));
212 else if (g_regex_match (self
->priv
->parent_regex
, output
, 0, &match_info
))
214 parents
= g_match_info_fetch (match_info
, 1);
215 parent_shas
= g_strsplit (parents
, " ", -1);
217 for (i
= 0; parent_shas
[i
]; i
++)
219 parent_revision
= g_hash_table_lookup (self
->priv
->revisions
,
222 if (!parent_revision
)
224 parent_revision
= git_revision_new ();
225 git_revision_set_sha (parent_revision
, parent_shas
[i
]);
226 g_hash_table_insert (self
->priv
->revisions
,
227 g_strdup (parent_shas
[i
]),
228 g_object_ref (parent_revision
));
231 git_revision_add_child (parent_revision
,
232 self
->priv
->current_revision
);
235 g_strfreev (parent_shas
);
237 else if (g_regex_match (self
->priv
->author_regex
, output
, 0, &match_info
))
239 author
= g_match_info_fetch (match_info
, 1);
240 git_revision_set_author (self
->priv
->current_revision
, author
);
244 else if (g_regex_match (self
->priv
->time_regex
, output
, 0, &match_info
))
246 time
= g_match_info_fetch (match_info
, 1);
247 git_revision_set_date (self
->priv
->current_revision
, atol (time
));
251 else if (g_regex_match (self
->priv
->short_log_regex
, output
, 0,
254 short_log
= g_match_info_fetch (match_info
, 1);
255 git_revision_set_short_log (self
->priv
->current_revision
, short_log
);
261 g_match_info_free (match_info
);
266 git_log_command_class_init (GitLogCommandClass
*klass
)
268 GObjectClass
* object_class
= G_OBJECT_CLASS (klass
);
269 GitCommandClass
* parent_class
= GIT_COMMAND_CLASS (klass
);
270 AnjutaCommandClass
*command_class
= ANJUTA_COMMAND_CLASS (klass
);
272 object_class
->finalize
= git_log_command_finalize
;
273 parent_class
->output_handler
= git_log_command_handle_output
;
274 command_class
->run
= git_log_command_run
;
279 git_log_command_new (const gchar
*working_directory
,
280 const gchar
*author
, const gchar
*grep
,
281 const gchar
*since_date
, const gchar
*until_date
,
282 const gchar
*since_commit
,
283 const gchar
*until_commit
)
287 self
= g_object_new (GIT_TYPE_LOG_COMMAND
,
288 "working-directory", working_directory
,
289 "single-line-output", TRUE
,
292 self
->priv
->author
= g_strdup (author
);
293 self
->priv
->grep
= g_strdup (grep
);
294 self
->priv
->since_date
= g_strdup (since_date
);
295 self
->priv
->until_date
= g_strdup (until_date
);
296 self
->priv
->since_commit
= g_strdup (since_commit
);
297 self
->priv
->until_commit
= g_strdup (until_commit
);
303 git_log_command_get_output_queue (GitLogCommand
*self
)
305 return self
->priv
->output_queue
;