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 #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
)
56 case ANJUTA_LAUNCHER_OUTPUT_STDOUT
:
57 GIT_COMMAND_GET_CLASS (self
)->output_handler (self
, chars
);
59 case ANJUTA_LAUNCHER_OUTPUT_STDERR
:
60 GIT_COMMAND_GET_CLASS (self
)->error_handler (self
, chars
);
67 /* Split the string up line by line. Works almost like g_strsplit, execpt the
68 * newlines are preserved. */
70 split_lines (const gchar
*string
)
74 const gchar
*remainder
;
80 string_pos
= strchr (string
, '\n');
88 /* Increment string_pos to preserve the newline. */
91 string_list
= g_list_prepend (string_list
, g_strndup (remainder
,
92 (string_pos
- remainder
)));
95 remainder
= string_pos
;
96 string_pos
= strchr (remainder
, '\n');
102 /* If there are no newlines in the string, just return a vector with
104 string_list
= g_list_prepend (string_list
, g_strdup (string
));
108 lines
= g_new (gchar
*, n
+ 1);
111 for (current_line
= string_list
;
113 current_line
= g_list_next (current_line
))
115 lines
[n
--] = current_line
->data
;
118 g_list_free (string_list
);
125 git_command_single_line_output_arrived (AnjutaLauncher
*launcher
,
126 AnjutaLauncherOutputType output_type
,
127 const gchar
*chars
, GitCommand
*self
)
129 void (*output_handler
) (GitCommand
*git_command
, const gchar
*output
);
131 gchar
**current_line
;
135 case ANJUTA_LAUNCHER_OUTPUT_STDOUT
:
136 output_handler
= GIT_COMMAND_GET_CLASS (self
)->output_handler
;
138 case ANJUTA_LAUNCHER_OUTPUT_STDERR
:
139 output_handler
= GIT_COMMAND_GET_CLASS (self
)->error_handler
;
142 output_handler
= NULL
;
148 lines
= split_lines (chars
);
150 for (current_line
= lines
; *current_line
; current_line
++)
151 output_handler (self
, *current_line
);
158 git_command_launch (GitCommand
*self
)
163 AnjutaLauncherOutputCallback callback
;
165 args
= g_new0 (gchar
*, self
->priv
->num_args
+ 2);
166 current_arg
= self
->priv
->args
;
173 args
[i
] = current_arg
->data
;
174 current_arg
= g_list_next (current_arg
);
178 if (self
->priv
->single_line_output
)
179 callback
= (AnjutaLauncherOutputCallback
) git_command_single_line_output_arrived
;
181 callback
= (AnjutaLauncherOutputCallback
) git_command_multi_line_output_arrived
;
183 if (!anjuta_launcher_execute_v (self
->priv
->launcher
,
188 git_command_append_error (self
, "Command execution failed.");
189 anjuta_command_notify_complete (ANJUTA_COMMAND (self
), 1);
192 /* Strings aren't copied; don't free them, just the vector */
197 git_command_start (AnjutaCommand
*command
)
199 /* We consider the command to be complete when the launcher notifies us of
200 * the child git process's completion, instead of when ::run returns. In
201 * this case, execute the command if ::run retruns 0. */
202 if (ANJUTA_COMMAND_GET_CLASS (command
)->run (command
) == 0)
203 git_command_launch (GIT_COMMAND (command
));
207 git_command_error_handler (GitCommand
*self
, const gchar
*output
)
209 GMatchInfo
*match_info
;
212 if (g_regex_match (self
->priv
->error_regex
, output
, 0, &match_info
))
214 error
= g_match_info_fetch (match_info
, 1);
215 g_match_info_free (match_info
);
217 g_string_append (self
->priv
->error_string
, error
);
223 git_command_child_exited (AnjutaLauncher
*launcher
, gint child_pid
, gint status
,
224 gulong time
, GitCommand
*self
)
226 if (strlen (self
->priv
->error_string
->str
) > 0)
228 anjuta_command_set_error_message (ANJUTA_COMMAND (self
),
229 self
->priv
->error_string
->str
);
232 anjuta_command_notify_complete (ANJUTA_COMMAND (self
),
233 (guint
) WEXITSTATUS (status
));
237 git_command_init (GitCommand
*self
)
239 self
->priv
= g_new0 (GitCommandPriv
, 1);
240 self
->priv
->launcher
= anjuta_launcher_new ();
242 g_signal_connect (G_OBJECT (self
->priv
->launcher
), "child-exited",
243 G_CALLBACK (git_command_child_exited
),
246 self
->priv
->error_regex
= g_regex_new ("^(?:warning|fatal): (.*)", 0, 0,
248 self
->priv
->error_string
= g_string_new ("");
249 self
->priv
->info_queue
= g_queue_new ();
253 git_command_finalize (GObject
*object
)
259 self
= GIT_COMMAND (object
);
261 current_arg
= self
->priv
->args
;
265 g_free (current_arg
->data
);
266 current_arg
= g_list_next (current_arg
);
269 current_info
= self
->priv
->info_queue
->head
;
273 g_free (current_info
->data
);
274 current_info
= g_list_next (current_info
);
277 g_object_unref (self
->priv
->launcher
);
278 g_regex_unref (self
->priv
->error_regex
);
279 g_string_free (self
->priv
->error_string
, TRUE
);
280 g_queue_free (self
->priv
->info_queue
);
281 g_free (self
->priv
->working_directory
);
284 G_OBJECT_CLASS (git_command_parent_class
)->finalize (object
);
288 git_command_set_property (GObject
*object
, guint prop_id
, const GValue
*value
,
293 self
= GIT_COMMAND (object
);
297 case PROP_WORKING_DIRECTORY
:
298 g_free (self
->priv
->working_directory
);
299 self
->priv
->working_directory
= g_value_dup_string (value
);
300 chdir (self
->priv
->working_directory
);
302 case PROP_SINGLE_LINE_OUTPUT
:
303 self
->priv
->single_line_output
= g_value_get_boolean (value
);
306 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, prop_id
, pspec
);
312 git_command_get_property (GObject
*object
, guint prop_id
, GValue
*value
,
317 self
= GIT_COMMAND (object
);
321 case PROP_WORKING_DIRECTORY
:
322 g_value_set_string (value
, self
->priv
->working_directory
);
325 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, prop_id
, pspec
);
331 git_command_class_init (GitCommandClass
*klass
)
333 GObjectClass
* object_class
= G_OBJECT_CLASS (klass
);
334 AnjutaCommandClass
* command_class
= ANJUTA_COMMAND_CLASS (klass
);
336 object_class
->finalize
= git_command_finalize
;
337 object_class
->set_property
= git_command_set_property
;
338 object_class
->get_property
= git_command_get_property
;
339 command_class
->start
= git_command_start
;
340 klass
->output_handler
= NULL
;
341 klass
->error_handler
= git_command_error_handler
;
343 g_object_class_install_property (object_class
, PROP_WORKING_DIRECTORY
,
344 g_param_spec_string ("working-directory",
346 "Directory to run git in.",
348 G_PARAM_CONSTRUCT_ONLY
| G_PARAM_READWRITE
));
350 g_object_class_install_property (object_class
, PROP_SINGLE_LINE_OUTPUT
,
351 g_param_spec_boolean ("single-line-output",
354 "handlers are given "
355 "output one line at "
358 G_PARAM_CONSTRUCT_ONLY
| G_PARAM_WRITABLE
));
363 git_command_add_arg (GitCommand
*self
, const gchar
*arg
)
365 self
->priv
->args
= g_list_append (self
->priv
->args
, g_strdup (arg
));
366 self
->priv
->num_args
++;
370 git_command_append_error (GitCommand
*self
, const gchar
*error_line
)
372 if (strlen (self
->priv
->error_string
->str
) > 0)
373 g_string_append_printf (self
->priv
->error_string
, "\n%s", error_line
);
375 g_string_append (self
->priv
->error_string
, error_line
);
379 git_command_push_info (GitCommand
*self
, const gchar
*info
)
381 g_queue_push_tail (self
->priv
->info_queue
, g_strdup (info
));
385 git_command_get_info_queue (GitCommand
*self
)
387 return self
->priv
->info_queue
;