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
;
54 G_DEFINE_TYPE (GitLogCommand
, git_log_command
, GIT_TYPE_COMMAND
);
57 git_log_command_init (GitLogCommand
*self
)
59 self
->priv
= g_new0 (GitLogCommandPriv
, 1);
60 self
->priv
->output_queue
= g_queue_new ();
61 self
->priv
->revisions
= g_hash_table_new_full (g_str_hash
, g_str_equal
,
62 g_free
, g_object_unref
);
63 self
->priv
->commit_regex
= g_regex_new (COMMIT_REGEX
, 0, 0, NULL
);
64 self
->priv
->parent_regex
= g_regex_new (PARENT_REGEX
, 0, 0, NULL
);
65 self
->priv
->author_regex
= g_regex_new (AUTHOR_REGEX
, 0, 0, NULL
);
66 self
->priv
->time_regex
= g_regex_new (TIME_REGEX
, 0, 0, NULL
);
67 self
->priv
->short_log_regex
= g_regex_new (SHORT_LOG_REGEX
, 0, 0, NULL
);
71 git_log_command_finalize (GObject
*object
)
74 GList
*current_output
;
76 self
= GIT_LOG_COMMAND (object
);
77 current_output
= self
->priv
->output_queue
->head
;
79 while (current_output
)
81 g_object_unref (current_output
->data
);
82 current_output
= g_list_next (current_output
);
85 g_queue_free (self
->priv
->output_queue
);
86 g_hash_table_destroy (self
->priv
->revisions
);
87 g_regex_unref (self
->priv
->commit_regex
);
88 g_regex_unref (self
->priv
->parent_regex
);
89 g_regex_unref (self
->priv
->author_regex
);
90 g_regex_unref (self
->priv
->time_regex
);
91 g_regex_unref (self
->priv
->short_log_regex
);
92 g_free (self
->priv
->path
);
94 g_free (self
->priv
->author
);
95 g_free (self
->priv
->grep
);
96 g_free (self
->priv
->since_date
);
97 g_free (self
->priv
->until_date
);
98 g_free (self
->priv
->since_commit
);
99 g_free (self
->priv
->until_commit
);
102 G_OBJECT_CLASS (git_log_command_parent_class
)->finalize (object
);
106 git_log_command_run (AnjutaCommand
*command
)
110 GString
*commit_range
;
112 self
= GIT_LOG_COMMAND (command
);
114 git_command_add_arg (GIT_COMMAND (command
), "rev-list");
115 git_command_add_arg (GIT_COMMAND (command
), "--topo-order");
116 git_command_add_arg (GIT_COMMAND (command
), "--pretty=format:parents %P%n"
122 if (self
->priv
->author
)
124 filter_arg
= g_strdup_printf ("--author=%s", self
->priv
->author
);
125 git_command_add_arg (GIT_COMMAND (command
), filter_arg
);
129 if (self
->priv
->grep
)
131 filter_arg
= g_strdup_printf ("--grep=%s", self
->priv
->grep
);
132 git_command_add_arg (GIT_COMMAND (command
), filter_arg
);
136 if (self
->priv
->since_date
)
138 filter_arg
= g_strdup_printf ("--since=%s", self
->priv
->since_date
);
139 git_command_add_arg (GIT_COMMAND (command
), filter_arg
);
143 if (self
->priv
->until_date
)
145 filter_arg
= g_strdup_printf ("--until=%s", self
->priv
->until_date
);
146 git_command_add_arg (GIT_COMMAND (command
), filter_arg
);
150 if (self
->priv
->since_commit
|| self
->priv
->until_commit
)
152 commit_range
= g_string_new ("");
154 /* Not the most elegant way of doing it... */
155 if (self
->priv
->since_commit
)
156 g_string_append (commit_range
, self
->priv
->since_commit
);
158 g_string_append (commit_range
, "..");
160 if (self
->priv
->until_commit
)
161 g_string_append (commit_range
, self
->priv
->until_commit
);
163 git_command_add_arg (GIT_COMMAND (command
), commit_range
->str
);
165 g_string_free (commit_range
, TRUE
);
168 git_command_add_arg (GIT_COMMAND (command
), "HEAD");
170 if (self
->priv
->path
)
172 git_command_add_arg (GIT_COMMAND (command
), "--");
173 git_command_add_arg (GIT_COMMAND (command
), self
->priv
->path
);
180 git_log_command_handle_output (GitCommand
*git_command
, const gchar
*output
)
183 GMatchInfo
*match_info
;
188 GitRevision
*parent_revision
;
193 self
= GIT_LOG_COMMAND (git_command
);
195 /* Entries are delimited by the hex value 0x0c */
196 if (*output
== 0x0c && self
->priv
->current_revision
)
198 g_queue_push_tail (self
->priv
->output_queue
,
199 self
->priv
->current_revision
);
200 anjuta_command_notify_data_arrived (ANJUTA_COMMAND (git_command
));
203 if (g_regex_match (self
->priv
->commit_regex
, output
, 0, &match_info
))
205 commit_sha
= g_match_info_fetch (match_info
, 1);
207 self
->priv
->current_revision
= g_hash_table_lookup (self
->priv
->revisions
,
210 if (!self
->priv
->current_revision
)
212 self
->priv
->current_revision
= git_revision_new ();
213 git_revision_set_sha (self
->priv
->current_revision
, commit_sha
);
214 g_hash_table_insert (self
->priv
->revisions
, g_strdup (commit_sha
),
215 g_object_ref (self
->priv
->current_revision
));
220 else if (g_regex_match (self
->priv
->parent_regex
, output
, 0, &match_info
))
222 parents
= g_match_info_fetch (match_info
, 1);
223 parent_shas
= g_strsplit (parents
, " ", -1);
225 for (i
= 0; parent_shas
[i
]; i
++)
227 parent_revision
= g_hash_table_lookup (self
->priv
->revisions
,
230 if (!parent_revision
)
232 parent_revision
= git_revision_new ();
233 git_revision_set_sha (parent_revision
, parent_shas
[i
]);
234 g_hash_table_insert (self
->priv
->revisions
,
235 g_strdup (parent_shas
[i
]),
236 g_object_ref (parent_revision
));
239 git_revision_add_child (parent_revision
,
240 self
->priv
->current_revision
);
243 g_strfreev (parent_shas
);
245 else if (g_regex_match (self
->priv
->author_regex
, output
, 0, &match_info
))
247 author
= g_match_info_fetch (match_info
, 1);
248 git_revision_set_author (self
->priv
->current_revision
, author
);
252 else if (g_regex_match (self
->priv
->time_regex
, output
, 0, &match_info
))
254 time
= g_match_info_fetch (match_info
, 1);
255 git_revision_set_date (self
->priv
->current_revision
, atol (time
));
259 else if (g_regex_match (self
->priv
->short_log_regex
, output
, 0,
262 short_log
= g_match_info_fetch (match_info
, 1);
263 git_revision_set_short_log (self
->priv
->current_revision
, short_log
);
269 g_match_info_free (match_info
);
274 git_log_command_class_init (GitLogCommandClass
*klass
)
276 GObjectClass
* object_class
= G_OBJECT_CLASS (klass
);
277 GitCommandClass
* parent_class
= GIT_COMMAND_CLASS (klass
);
278 AnjutaCommandClass
*command_class
= ANJUTA_COMMAND_CLASS (klass
);
280 object_class
->finalize
= git_log_command_finalize
;
281 parent_class
->output_handler
= git_log_command_handle_output
;
282 command_class
->run
= git_log_command_run
;
287 git_log_command_new (const gchar
*working_directory
,
289 const gchar
*author
, const gchar
*grep
,
290 const gchar
*since_date
, const gchar
*until_date
,
291 const gchar
*since_commit
,
292 const gchar
*until_commit
)
296 self
= g_object_new (GIT_TYPE_LOG_COMMAND
,
297 "working-directory", working_directory
,
298 "single-line-output", TRUE
,
301 self
->priv
->author
= g_strdup (author
);
302 self
->priv
->path
= g_strdup (path
);
303 self
->priv
->grep
= g_strdup (grep
);
304 self
->priv
->since_date
= g_strdup (since_date
);
305 self
->priv
->until_date
= g_strdup (until_date
);
306 self
->priv
->since_commit
= g_strdup (since_commit
);
307 self
->priv
->until_commit
= g_strdup (until_commit
);
313 git_log_command_get_output_queue (GitLogCommand
*self
)
315 return self
->priv
->output_queue
;