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
;
45 G_DEFINE_TYPE (GitLogCommand
, git_log_command
, GIT_TYPE_COMMAND
);
48 git_log_command_init (GitLogCommand
*self
)
50 self
->priv
= g_new0 (GitLogCommandPriv
, 1);
51 self
->priv
->output_queue
= g_queue_new ();
52 self
->priv
->revisions
= g_hash_table_new_full (g_str_hash
, g_str_equal
,
53 g_free
, g_object_unref
);
54 self
->priv
->commit_regex
= g_regex_new (COMMIT_REGEX
, 0, 0, NULL
);
55 self
->priv
->parent_regex
= g_regex_new (PARENT_REGEX
, 0, 0, NULL
);
56 self
->priv
->author_regex
= g_regex_new (AUTHOR_REGEX
, 0, 0, NULL
);
57 self
->priv
->time_regex
= g_regex_new (TIME_REGEX
, 0, 0, NULL
);
58 self
->priv
->short_log_regex
= g_regex_new (SHORT_LOG_REGEX
, 0, 0, NULL
);
62 git_log_command_finalize (GObject
*object
)
65 GList
*current_output
;
67 self
= GIT_LOG_COMMAND (object
);
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
);
85 G_OBJECT_CLASS (git_log_command_parent_class
)->finalize (object
);
89 git_log_command_run (AnjutaCommand
*command
)
91 git_command_add_arg (GIT_COMMAND (command
), "rev-list");
92 git_command_add_arg (GIT_COMMAND (command
), "--topo-order");
93 git_command_add_arg (GIT_COMMAND (command
), "--pretty=format:parents %P%n"
98 git_command_add_arg (GIT_COMMAND (command
), "HEAD");
104 git_log_command_handle_output (GitCommand
*git_command
, const gchar
*output
)
107 GMatchInfo
*match_info
;
112 GitRevision
*parent_revision
;
117 self
= GIT_LOG_COMMAND (git_command
);
119 /* Entries are delimited by the hex value 0x0c */
120 if (*output
== 0x0c && self
->priv
->current_revision
)
122 g_queue_push_tail (self
->priv
->output_queue
,
123 self
->priv
->current_revision
);
124 anjuta_command_notify_data_arrived (ANJUTA_COMMAND (git_command
));
127 if (g_regex_match (self
->priv
->commit_regex
, output
, 0, &match_info
))
129 commit_sha
= g_match_info_fetch (match_info
, 1);
131 self
->priv
->current_revision
= g_hash_table_lookup (self
->priv
->revisions
,
134 if (!self
->priv
->current_revision
)
136 self
->priv
->current_revision
= git_revision_new ();
137 git_revision_set_sha (self
->priv
->current_revision
, commit_sha
);
138 g_hash_table_insert (self
->priv
->revisions
, g_strdup (commit_sha
),
139 g_object_ref (self
->priv
->current_revision
));
144 else if (g_regex_match (self
->priv
->parent_regex
, output
, 0, &match_info
))
146 parents
= g_match_info_fetch (match_info
, 1);
147 parent_shas
= g_strsplit (parents
, " ", -1);
149 for (i
= 0; parent_shas
[i
]; i
++)
151 parent_revision
= g_hash_table_lookup (self
->priv
->revisions
,
154 if (!parent_revision
)
156 parent_revision
= git_revision_new ();
157 git_revision_set_sha (parent_revision
, parent_shas
[i
]);
158 g_hash_table_insert (self
->priv
->revisions
,
159 g_strdup (parent_shas
[i
]),
160 g_object_ref (parent_revision
));
163 git_revision_add_child (parent_revision
,
164 self
->priv
->current_revision
);
167 g_strfreev (parent_shas
);
169 else if (g_regex_match (self
->priv
->author_regex
, output
, 0, &match_info
))
171 author
= g_match_info_fetch (match_info
, 1);
172 git_revision_set_author (self
->priv
->current_revision
, author
);
176 else if (g_regex_match (self
->priv
->time_regex
, output
, 0, &match_info
))
178 time
= g_match_info_fetch (match_info
, 1);
179 git_revision_set_date (self
->priv
->current_revision
, atol (time
));
183 else if (g_regex_match (self
->priv
->short_log_regex
, output
, 0,
186 short_log
= g_match_info_fetch (match_info
, 1);
187 git_revision_set_short_log (self
->priv
->current_revision
, short_log
);
193 g_match_info_free (match_info
);
198 git_log_command_class_init (GitLogCommandClass
*klass
)
200 GObjectClass
* object_class
= G_OBJECT_CLASS (klass
);
201 GitCommandClass
* parent_class
= GIT_COMMAND_CLASS (klass
);
202 AnjutaCommandClass
*command_class
= ANJUTA_COMMAND_CLASS (klass
);
204 object_class
->finalize
= git_log_command_finalize
;
205 parent_class
->output_handler
= git_log_command_handle_output
;
206 command_class
->run
= git_log_command_run
;
211 git_log_command_new (const gchar
*working_directory
)
213 return g_object_new (GIT_TYPE_LOG_COMMAND
,
214 "working-directory", working_directory
,
215 "single-line-output", TRUE
,
220 git_log_command_get_output_queue (GitLogCommand
*self
)
222 return self
->priv
->output_queue
;