1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
4 * Copyright (C) James Liggett 2008 <jrliggett@cox.net>
6 * anjuta 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 * anjuta 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 anjuta. If not, write to:
20 * The Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor
22 * Boston, MA 02110-1301, USA.
25 #include "git-command.h"
31 PROP_WORKING_DIRECTORY
,
32 PROP_SINGLE_LINE_OUTPUT
35 struct _GitCommandPriv
37 AnjutaLauncher
*launcher
;
40 gchar
*working_directory
;
42 GString
*error_string
;
44 gboolean single_line_output
;
47 G_DEFINE_TYPE (GitCommand
, git_command
, ANJUTA_TYPE_SYNC_COMMAND
);
50 git_command_multi_line_output_arrived (AnjutaLauncher
*launcher
,
51 AnjutaLauncherOutputType output_type
,
52 const gchar
*chars
, GitCommand
*self
)
54 GitCommandClass
*klass
;
56 klass
= GIT_COMMAND_GET_CLASS (self
);
60 case ANJUTA_LAUNCHER_OUTPUT_STDOUT
:
61 if (klass
->output_handler
)
62 GIT_COMMAND_GET_CLASS (self
)->output_handler (self
, chars
);
64 case ANJUTA_LAUNCHER_OUTPUT_STDERR
:
65 GIT_COMMAND_GET_CLASS (self
)->error_handler (self
, chars
);
72 /* Split the string up line by line. Works almost like g_strsplit, execpt the
73 * newlines are preserved. */
75 split_lines (const gchar
*string
)
79 const gchar
*remainder
;
85 string_pos
= strchr (string
, '\n');
93 /* Increment string_pos to preserve the newline. */
96 string_list
= g_list_prepend (string_list
, g_strndup (remainder
,
97 (string_pos
- remainder
)));
100 remainder
= string_pos
;
101 string_pos
= strchr (remainder
, '\n');
107 /* If there are no newlines in the string, just return a vector with
109 string_list
= g_list_prepend (string_list
, g_strdup (string
));
113 lines
= g_new (gchar
*, n
+ 1);
116 for (current_line
= string_list
;
118 current_line
= g_list_next (current_line
))
120 lines
[n
--] = current_line
->data
;
123 g_list_free (string_list
);
130 git_command_single_line_output_arrived (AnjutaLauncher
*launcher
,
131 AnjutaLauncherOutputType output_type
,
132 const gchar
*chars
, GitCommand
*self
)
134 void (*output_handler
) (GitCommand
*git_command
, const gchar
*output
);
136 gchar
**current_line
;
140 case ANJUTA_LAUNCHER_OUTPUT_STDOUT
:
141 output_handler
= GIT_COMMAND_GET_CLASS (self
)->output_handler
;
143 case ANJUTA_LAUNCHER_OUTPUT_STDERR
:
144 output_handler
= GIT_COMMAND_GET_CLASS (self
)->error_handler
;
147 output_handler
= NULL
;
153 lines
= split_lines (chars
);
155 for (current_line
= lines
; *current_line
; current_line
++)
156 output_handler (self
, *current_line
);
163 git_command_launch (GitCommand
*self
)
168 AnjutaLauncherOutputCallback callback
;
170 args
= g_new0 (gchar
*, self
->priv
->num_args
+ 2);
171 current_arg
= self
->priv
->args
;
178 args
[i
] = current_arg
->data
;
179 current_arg
= g_list_next (current_arg
);
183 if (self
->priv
->single_line_output
)
184 callback
= (AnjutaLauncherOutputCallback
) git_command_single_line_output_arrived
;
186 callback
= (AnjutaLauncherOutputCallback
) git_command_multi_line_output_arrived
;
188 if (!anjuta_launcher_execute_v (self
->priv
->launcher
,
193 git_command_append_error (self
, "Command execution failed.");
194 anjuta_command_notify_complete (ANJUTA_COMMAND (self
), 1);
197 /* Strings aren't copied; don't free them, just the vector */
202 git_command_start (AnjutaCommand
*command
)
204 /* We consider the command to be complete when the launcher notifies us of
205 * the child git process's completion, instead of when ::run returns. In
206 * this case, execute the command if ::run retruns 0. */
207 if (ANJUTA_COMMAND_GET_CLASS (command
)->run (command
) == 0)
208 git_command_launch (GIT_COMMAND (command
));
212 git_command_error_handler (GitCommand
*self
, const gchar
*output
)
214 GMatchInfo
*match_info
;
217 if (g_regex_match (self
->priv
->error_regex
, output
, 0, &match_info
))
219 error
= g_match_info_fetch (match_info
, 1);
220 g_match_info_free (match_info
);
222 g_string_append (self
->priv
->error_string
, error
);
228 git_command_child_exited (AnjutaLauncher
*launcher
, gint child_pid
, gint status
,
229 gulong time
, GitCommand
*self
)
231 if (strlen (self
->priv
->error_string
->str
) > 0)
233 anjuta_command_set_error_message (ANJUTA_COMMAND (self
),
234 self
->priv
->error_string
->str
);
237 anjuta_command_notify_complete (ANJUTA_COMMAND (self
),
238 (guint
) WEXITSTATUS (status
));
242 git_command_init (GitCommand
*self
)
244 self
->priv
= g_new0 (GitCommandPriv
, 1);
245 self
->priv
->launcher
= anjuta_launcher_new ();
247 g_signal_connect (G_OBJECT (self
->priv
->launcher
), "child-exited",
248 G_CALLBACK (git_command_child_exited
),
251 self
->priv
->error_regex
= g_regex_new ("^(?:warning|fatal): (.*)", 0, 0,
253 self
->priv
->error_string
= g_string_new ("");
254 self
->priv
->info_queue
= g_queue_new ();
258 git_command_finalize (GObject
*object
)
264 self
= GIT_COMMAND (object
);
266 current_arg
= self
->priv
->args
;
270 g_free (current_arg
->data
);
271 current_arg
= g_list_next (current_arg
);
274 current_info
= self
->priv
->info_queue
->head
;
278 g_free (current_info
->data
);
279 current_info
= g_list_next (current_info
);
282 g_object_unref (self
->priv
->launcher
);
283 g_regex_unref (self
->priv
->error_regex
);
284 g_string_free (self
->priv
->error_string
, TRUE
);
285 g_queue_free (self
->priv
->info_queue
);
286 g_free (self
->priv
->working_directory
);
289 G_OBJECT_CLASS (git_command_parent_class
)->finalize (object
);
293 git_command_set_property (GObject
*object
, guint prop_id
, const GValue
*value
,
298 self
= GIT_COMMAND (object
);
302 case PROP_WORKING_DIRECTORY
:
303 g_free (self
->priv
->working_directory
);
304 self
->priv
->working_directory
= g_value_dup_string (value
);
305 chdir (self
->priv
->working_directory
);
307 case PROP_SINGLE_LINE_OUTPUT
:
308 self
->priv
->single_line_output
= g_value_get_boolean (value
);
311 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, prop_id
, pspec
);
317 git_command_get_property (GObject
*object
, guint prop_id
, GValue
*value
,
322 self
= GIT_COMMAND (object
);
326 case PROP_WORKING_DIRECTORY
:
327 g_value_set_string (value
, self
->priv
->working_directory
);
330 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, prop_id
, pspec
);
336 git_command_class_init (GitCommandClass
*klass
)
338 GObjectClass
* object_class
= G_OBJECT_CLASS (klass
);
339 AnjutaCommandClass
* command_class
= ANJUTA_COMMAND_CLASS (klass
);
341 object_class
->finalize
= git_command_finalize
;
342 object_class
->set_property
= git_command_set_property
;
343 object_class
->get_property
= git_command_get_property
;
344 command_class
->start
= git_command_start
;
345 klass
->output_handler
= NULL
;
346 klass
->error_handler
= git_command_error_handler
;
348 g_object_class_install_property (object_class
, PROP_WORKING_DIRECTORY
,
349 g_param_spec_string ("working-directory",
351 "Directory to run git in.",
353 G_PARAM_CONSTRUCT_ONLY
| G_PARAM_READWRITE
));
355 g_object_class_install_property (object_class
, PROP_SINGLE_LINE_OUTPUT
,
356 g_param_spec_boolean ("single-line-output",
359 "handlers are given "
360 "output one line at "
363 G_PARAM_CONSTRUCT_ONLY
| G_PARAM_WRITABLE
));
368 git_command_add_arg (GitCommand
*self
, const gchar
*arg
)
370 self
->priv
->args
= g_list_append (self
->priv
->args
, g_strdup (arg
));
371 self
->priv
->num_args
++;
375 git_command_add_list_to_args (GitCommand
*self
, GList
*list
)
383 self
->priv
->args
= g_list_append (self
->priv
->args
,
384 g_strdup (current_arg
->data
));
385 self
->priv
->num_args
++;
387 current_arg
= g_list_next (current_arg
);
392 git_command_append_error (GitCommand
*self
, const gchar
*error_line
)
394 if (strlen (self
->priv
->error_string
->str
) > 0)
395 g_string_append_printf (self
->priv
->error_string
, "\n%s", error_line
);
397 g_string_append (self
->priv
->error_string
, error_line
);
401 git_command_push_info (GitCommand
*self
, const gchar
*info
)
403 g_queue_push_tail (self
->priv
->info_queue
, g_strdup (info
));
404 anjuta_command_notify_data_arrived (ANJUTA_COMMAND (self
));
408 git_command_get_info_queue (GitCommand
*self
)
410 return self
->priv
->info_queue
;
414 git_command_send_output_to_info (GitCommand
*git_command
, const gchar
*output
)
419 /* Strip off the newline before sending it to the queue */
420 newline
= strchr (output
, '\n');
423 info_string
= g_strndup (output
, (newline
- output
));
425 info_string
= g_strdup (output
);
427 git_command_push_info (git_command
, info_string
);
431 git_command_copy_path_list (GList
*list
)
441 new_list
= g_list_append (new_list
, g_strdup (current_path
->data
));
442 current_path
= g_list_next (current_path
);
449 git_command_free_path_list (GList
*list
)
457 g_free (current_path
->data
);
458 current_path
= g_list_next (current_path
);