[gitg] Improved GitgRunner/GitgCommand/GitgShell
- From: Jesse van den Kieboom <jessevdk src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gitg] Improved GitgRunner/GitgCommand/GitgShell
- Date: Sat, 6 Nov 2010 11:23:13 +0000 (UTC)
commit f9ef65b59dbe9724dc9578567b37e7ecae3f5235
Author: Jesse van den Kieboom <jessevdk gnome org>
Date: Mon Oct 25 09:50:05 2010 +0200
Improved GitgRunner/GitgCommand/GitgShell
Makefile.am | 2 +-
configure.ac | 2 +
gitg/gitg-branch-actions.c | 548 ++++++++++++-------
gitg/gitg-branch-actions.h | 18 +-
gitg/gitg-commit-view.c | 119 +++--
gitg/gitg-dnd.c | 15 +-
gitg/gitg-repository-dialog.c | 65 ++-
gitg/gitg-revision-changes-panel.c | 184 ++++---
gitg/gitg-revision-details-panel.c | 62 +-
gitg/gitg-revision-files-panel.c | 60 +-
gitg/gitg-window.c | 33 +-
gitg/gitg-window.h | 17 +-
libgitg/Makefile.am | 12 +-
libgitg/gitg-command.c | 491 +++++++++++++++++
libgitg/gitg-command.h | 76 +++
libgitg/gitg-commit.c | 1050 +++++++++++++++++++++++-------------
libgitg/gitg-commit.h | 60 ++-
libgitg/gitg-config.c | 179 +++----
libgitg/gitg-config.h | 35 +-
libgitg/gitg-io.c | 406 ++++++++++++++
libgitg/gitg-io.h | 70 +++
libgitg/gitg-line-parser.c | 452 ++++++++++++++++
libgitg/gitg-line-parser.h | 45 ++
libgitg/gitg-repository.c | 433 +++------------
libgitg/gitg-repository.h | 28 +-
libgitg/gitg-runner.c | 1016 ++++++++++-------------------------
libgitg/gitg-runner.h | 93 +---
libgitg/gitg-shell.c | 1052 ++++++++++++++++++++++++++++++++++++
libgitg/gitg-shell.h | 153 ++++++
tests/Makefile.am | 12 +
tests/shell.c | 273 ++++++++++
tools/Makefile.am | 10 +
tools/gitg-shell.c | 206 +++++++
33 files changed, 5142 insertions(+), 2135 deletions(-)
---
diff --git a/Makefile.am b/Makefile.am
index 4e97269..a3a9d14 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,6 +1,6 @@
## Process this file with automake to produce Makefile.in
-SUBDIRS = libgitg gitg data po
+SUBDIRS = libgitg gitg data po tests tools
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = libgitg-1.0.pc
diff --git a/configure.ac b/configure.ac
index 5aa6cd5..abdba9a 100644
--- a/configure.ac
+++ b/configure.ac
@@ -144,6 +144,8 @@ data/Makefile
data/gitg.desktop.in
data/icons/Makefile
po/Makefile.in
+tests/Makefile
+tools/Makefile
])
AC_OUTPUT
diff --git a/gitg/gitg-branch-actions.c b/gitg/gitg-branch-actions.c
index 17ef96e..12da232 100644
--- a/gitg/gitg-branch-actions.c
+++ b/gitg/gitg-branch-actions.c
@@ -38,7 +38,7 @@ typedef void (*ProgressCallback) (GitgWindow *window, GitgProgress progress, gpo
typedef struct
{
GitgWindow *window;
- GitgRunner *runner;
+ GitgShell *shell;
ProgressCallback callback;
gpointer callback_data;
@@ -59,7 +59,7 @@ free_progress_info (ProgressInfo *info)
gtk_widget_destroy (GTK_WIDGET (info->dialog));
- g_object_unref (info->runner);
+ g_object_unref (info->shell);
g_slice_free (ProgressInfo, info);
}
@@ -81,7 +81,7 @@ parse_valist (va_list ap)
}
static void
-on_progress_end (GitgRunner *runner, gboolean cancelled, ProgressInfo *info)
+on_progress_end (GitgShell *shell, gboolean cancelled, ProgressInfo *info)
{
GitgProgress progress;
@@ -89,7 +89,7 @@ on_progress_end (GitgRunner *runner, gboolean cancelled, ProgressInfo *info)
{
progress = GITG_PROGRESS_CANCELLED;
}
- else if (gitg_runner_get_exit_status (runner) != 0)
+ else if (gitg_io_get_exit_status (GITG_IO (shell)) != 0)
{
progress = GITG_PROGRESS_ERROR;
}
@@ -109,7 +109,7 @@ on_progress_end (GitgRunner *runner, gboolean cancelled, ProgressInfo *info)
static void
on_progress_response (GtkDialog *dialog, GtkResponseType response, ProgressInfo *info)
{
- gitg_runner_cancel (info->runner);
+ gitg_io_cancel (GITG_IO (info->shell));
}
static gboolean
@@ -119,7 +119,7 @@ on_progress_timeout (ProgressInfo *info)
return TRUE;
}
-static GitgRunner *
+static GitgShell *
run_progress (GitgWindow *window,
gchar const *title,
gchar const *message,
@@ -129,19 +129,18 @@ run_progress (GitgWindow *window,
{
va_list ap;
- // Create runner
va_start (ap, callback_data);
- GitgRunner *runner = gitg_runner_new (1000);
+ GitgShell *shell = gitg_shell_new (1000);
gchar const **argv = parse_valist (ap);
- if (!gitg_repository_run_command (gitg_window_get_repository (window),
- runner,
- argv,
- NULL))
+ GitgCommand *cmd = gitg_command_new (gitg_window_get_repository (window),
+ (gchar const * const *)argv);
+
+ if (!gitg_shell_run (shell, cmd, NULL))
{
g_free (argv);
- g_object_unref (runner);
+ g_object_unref (shell);
callback (window, GITG_PROGRESS_ERROR, callback_data);
@@ -183,14 +182,14 @@ run_progress (GitgWindow *window,
info->callback = callback;
info->callback_data = callback_data;
info->window = window;
- info->runner = g_object_ref (runner);
+ info->shell = g_object_ref (shell);
info->timeout_id = g_timeout_add (100, (GSourceFunc)on_progress_timeout, info);
g_signal_connect (dlg, "response", G_CALLBACK (on_progress_response), info);
- g_signal_connect (runner, "end-loading", G_CALLBACK (on_progress_end), info);
+ g_signal_connect (shell, "end", G_CALLBACK (on_progress_end), info);
- return runner;
+ return shell;
}
static gint
@@ -257,14 +256,19 @@ message_dialog (GitgWindow *window,
return ret;
}
-static GitgRunner *
+static GitgShell *
remove_local_branch (GitgWindow *window,
GitgRef *ref)
{
gchar const *name = gitg_ref_get_shortname (ref);
GitgRepository *repository = gitg_window_get_repository (window);
- if (!gitg_repository_commandv (repository, NULL, "branch", "-d", name, NULL))
+ if (!gitg_shell_run_sync (gitg_command_newv (repository,
+ "branch",
+ "-d",
+ name,
+ NULL),
+ NULL))
{
gint ret = message_dialog (window,
GTK_MESSAGE_ERROR,
@@ -275,7 +279,12 @@ remove_local_branch (GitgWindow *window,
if (ret == GTK_RESPONSE_ACCEPT)
{
- if (!gitg_repository_commandv (repository, NULL, "branch", "-D", name, NULL))
+ if (!gitg_shell_run_sync (gitg_command_newv (repository,
+ "branch",
+ "-D",
+ name,
+ NULL),
+ NULL))
{
message_dialog (window,
GTK_MESSAGE_ERROR,
@@ -325,7 +334,7 @@ on_remove_remote_result (GitgWindow *window, GitgProgress progress, gpointer dat
gitg_ref_free (ref);
}
-static GitgRunner *
+static GitgShell *
remove_remote_branch (GitgWindow *window,
GitgRef *ref)
{
@@ -346,7 +355,7 @@ remove_remote_branch (GitgWindow *window,
gchar const *local = gitg_ref_get_local_name (ref);
gchar *rm = g_strconcat (":", local, NULL);
- GitgRunner *ret;
+ GitgShell *ret;
gchar *message = g_strdup_printf ("Removing remote branch `%s'", name);
ret = run_progress (window,
@@ -368,14 +377,15 @@ get_stash_refspec (GitgRepository *repository, GitgRef *stash)
{
gchar **out;
- out = gitg_repository_command_with_outputv (repository,
- NULL,
- "log",
- "--no-color",
- "--pretty=oneline",
- "-g",
- "refs/stash",
- NULL);
+ out = gitg_shell_run_sync_with_output (gitg_command_newv (repository,
+ "log",
+ "--no-color",
+ "--pretty=oneline",
+ "-g",
+ "refs/stash",
+ NULL),
+ FALSE,
+ NULL);
gchar **ptr = out;
gchar *sha1 = gitg_hash_hash_to_sha1_new (gitg_ref_get_hash (stash));
@@ -403,7 +413,7 @@ get_stash_refspec (GitgRepository *repository, GitgRef *stash)
return ret;
}
-static GitgRunner *
+static GitgShell *
remove_stash (GitgWindow *window, GitgRef *ref)
{
gint r = message_dialog (window,
@@ -425,14 +435,14 @@ remove_stash (GitgWindow *window, GitgRef *ref)
return NULL;
}
- if (!gitg_repository_commandv (repository,
- NULL,
- "reflog",
- "delete",
- "--updateref",
- "--rewrite",
- spec,
- NULL))
+ if (!gitg_shell_run_sync (gitg_command_newv (repository,
+ "reflog",
+ "delete",
+ "--updateref",
+ "--rewrite",
+ spec,
+ NULL),
+ NULL))
{
message_dialog (window,
GTK_MESSAGE_ERROR,
@@ -442,19 +452,19 @@ remove_stash (GitgWindow *window, GitgRef *ref)
}
else
{
- if (!gitg_repository_commandv (repository,
- NULL,
- "rev-parse",
- "--verify",
- "refs/stash {0}",
- NULL))
+ if (!gitg_shell_run_sync (gitg_command_newv (repository,
+ "rev-parse",
+ "--verify",
+ "refs/stash {0}",
+ NULL),
+ NULL))
{
- gitg_repository_commandv (repository,
- NULL,
- "update-ref",
- "-d",
- "refs/stash",
- NULL);
+ gitg_shell_run_sync (gitg_command_newv (repository,
+ "update-ref",
+ "-d",
+ "refs/stash",
+ NULL),
+ NULL);
}
gitg_repository_reload (repository);
@@ -464,7 +474,7 @@ remove_stash (GitgWindow *window, GitgRef *ref)
return NULL;
}
-static GitgRunner *
+static GitgShell *
remove_tag (GitgWindow *window, GitgRef *ref)
{
gchar const *name = gitg_ref_get_shortname (ref);
@@ -484,12 +494,12 @@ remove_tag (GitgWindow *window, GitgRef *ref)
GitgRepository *repository = gitg_window_get_repository (window);
- if (!gitg_repository_commandv (repository,
- NULL,
- "tag",
- "-d",
- name,
- NULL))
+ if (!gitg_shell_run_sync (gitg_command_newv (repository,
+ "tag",
+ "-d",
+ name,
+ NULL),
+ NULL))
{
message = g_strdup_printf (_ ("The tag <%s> could not be successfully removed"),
name);
@@ -508,7 +518,7 @@ remove_tag (GitgWindow *window, GitgRef *ref)
}
}
-GitgRunner *
+GitgShell *
gitg_branch_actions_remove (GitgWindow *window,
GitgRef *ref)
{
@@ -516,7 +526,7 @@ gitg_branch_actions_remove (GitgWindow *window,
g_return_val_if_fail (ref != NULL, NULL);
GitgRef *cp = gitg_ref_copy (ref);
- GitgRunner *ret = NULL;
+ GitgShell *ret = NULL;
switch (gitg_ref_get_ref_type (cp))
{
@@ -540,7 +550,7 @@ gitg_branch_actions_remove (GitgWindow *window,
return ret;
}
-static GitgRunner *
+static GitgShell *
rename_branch (GitgWindow *window,
GitgRef *ref,
const gchar *newname)
@@ -548,7 +558,13 @@ rename_branch (GitgWindow *window,
gchar const *oldname = gitg_ref_get_shortname (ref);
GitgRepository *repository = gitg_window_get_repository (window);
- if (!gitg_repository_commandv (repository, NULL, "branch", "-m", oldname, newname, NULL))
+ if (!gitg_shell_run_sync (gitg_command_newv (repository,
+ "branch",
+ "-m",
+ oldname,
+ newname,
+ NULL),
+ NULL))
{
gint ret = message_dialog (window,
GTK_MESSAGE_ERROR,
@@ -559,7 +575,13 @@ rename_branch (GitgWindow *window,
if (ret == GTK_RESPONSE_ACCEPT)
{
- if (!gitg_repository_commandv (repository, NULL, "branch", "-M", oldname, newname, NULL))
+ if (!gitg_shell_run_sync (gitg_command_newv (repository,
+ "branch",
+ "-M",
+ oldname,
+ newname,
+ NULL),
+ NULL))
{
message_dialog (window,
GTK_MESSAGE_ERROR,
@@ -635,7 +657,7 @@ rename_dialog (GitgWindow *window, const gchar *oldname)
return newname;
}
-GitgRunner *
+GitgShell *
gitg_branch_actions_rename (GitgWindow *window,
GitgRef *ref)
{
@@ -649,7 +671,7 @@ gitg_branch_actions_rename (GitgWindow *window,
if (newname)
{
GitgRef *cp = gitg_ref_copy (ref);
- GitgRunner *ret = NULL;
+ GitgShell *ret = NULL;
ret = rename_branch (window, cp, newname);
gitg_ref_free (cp);
g_free (newname);
@@ -661,13 +683,13 @@ gitg_branch_actions_rename (GitgWindow *window,
}
static void
-reset_buffer (GitgRunner *runner, GString *buffer)
+reset_buffer (GitgShell *shell, GString *buffer)
{
g_string_erase (buffer, 0, -1);
}
static void
-update_buffer (GitgRunner *runner, gchar **lines, GString *buffer)
+update_buffer (GitgShell *shell, gchar **lines, GString *buffer)
{
gchar **ptr = lines;
@@ -686,12 +708,26 @@ update_buffer (GitgRunner *runner, gchar **lines, GString *buffer)
static gboolean
no_changes (GitgRepository *repository)
{
- return gitg_repository_commandv (repository, NULL,
- "update-index", "--refresh", NULL) &&
- gitg_repository_commandv (repository, NULL,
- "diff-files", "--quiet", NULL) &&
- gitg_repository_commandv (repository, NULL,
- "diff-index", "--cached", "--quiet", "HEAD", "--", NULL);
+ return gitg_shell_run_sync (gitg_command_newv (repository,
+ "update-index",
+ "--refresh",
+ NULL),
+ NULL) &&
+ gitg_shell_run_sync (gitg_command_newv (repository,
+ "diff-files",
+ "--no-ext-diff",
+ "--quiet",
+ NULL),
+ NULL) &&
+ gitg_shell_run_sync (gitg_command_newv (repository,
+ "diff-index",
+ "--no-ext-diff",
+ "--cached",
+ "--quiet",
+ "HEAD",
+ "--",
+ NULL),
+ NULL);
}
static gboolean
@@ -705,11 +741,11 @@ stash_changes_real (GitgWindow *window, gchar **ref, gboolean storeref)
gchar *msg = NULL;
gboolean showerror = FALSE;
- GitgRunner *runner = gitg_runner_new_synchronized (1000);
+ GitgShell *shell = gitg_shell_new_synchronized (1000);
GString *buffer = g_string_new ("");
- g_signal_connect (runner, "begin-loading", G_CALLBACK (reset_buffer), buffer);
- g_signal_connect (runner, "update", G_CALLBACK (update_buffer), buffer);
+ g_signal_connect (shell, "begin", G_CALLBACK (reset_buffer), buffer);
+ g_signal_connect (shell, "update", G_CALLBACK (update_buffer), buffer);
gchar const *secondary;
@@ -734,9 +770,17 @@ stash_changes_real (GitgWindow *window, gchar **ref, gboolean storeref)
goto cleanup;
}
- gitg_repository_run_commandv (repository, runner, NULL,
- "log", "--no-color", "--abbrev-commit",
- "--pretty=oneline", "-n", "1", "HEAD", NULL);
+ gitg_shell_run (shell,
+ gitg_command_newv (repository,
+ "log",
+ "--no-color",
+ "--abbrev-commit",
+ "--pretty=oneline",
+ "-n",
+ "1",
+ "HEAD",
+ NULL),
+ NULL);
GitgRef *working = gitg_repository_get_current_working_ref (repository);
@@ -750,8 +794,11 @@ stash_changes_real (GitgWindow *window, gchar **ref, gboolean storeref)
}
// Create tree object of the current index
- gitg_repository_run_commandv (repository, runner, NULL,
- "write-tree", NULL);
+ gitg_shell_run (shell,
+ gitg_command_newv (repository,
+ "write-tree",
+ NULL),
+ NULL);
if (buffer->len == 0)
{
@@ -765,10 +812,22 @@ stash_changes_real (GitgWindow *window, gchar **ref, gboolean storeref)
head = gitg_repository_parse_head (repository);
gchar *idxmsg = g_strconcat ("index on ", msg, NULL);
- gitg_repository_run_command_with_inputv (repository, runner, idxmsg, NULL,
- "commit-tree", tree, "-p", head, NULL);
+
+ GInputStream *inp = g_memory_input_stream_new_from_data (idxmsg, -1, NULL);
+ gitg_io_set_input (GITG_IO (shell), inp);
+ g_object_unref (inp);
+
+ gitg_shell_run (shell,
+ gitg_command_newv (repository,
+ "commit-tree",
+ tree,
+ "-p",
+ head,
+ NULL),
+ NULL);
g_free (idxmsg);
+ gitg_io_set_input (GITG_IO (shell), NULL);
if (buffer->len == 0)
{
@@ -814,23 +873,48 @@ stash_changes_real (GitgWindow *window, gchar **ref, gboolean storeref)
}
tmpname = g_file_get_path (customindex);
- gitg_runner_add_environment (runner, "GIT_INDEX_FILE", tmpname);
+
+ GitgCommand *cmd_read_tree = gitg_command_newv (repository,
+ "read-tree",
+ "-m",
+ tree,
+ NULL);
+
+ gitg_command_add_environmentv (cmd_read_tree,
+ "GIT_INDEX_FILE",
+ tmpname,
+ NULL);
+
+ GitgCommand *cmd_add = gitg_command_newv (repository,
+ "add",
+ "-u",
+ NULL);
+
+ gitg_command_add_environmentv (cmd_add,
+ "GIT_INDEX_FILE",
+ tmpname,
+ NULL);
+
+ GitgCommand *cmd_write_tree = gitg_command_newv (repository,
+ "write-tree",
+ NULL);
+
+ gitg_command_add_environmentv (cmd_write_tree,
+ "GIT_INDEX_FILE",
+ tmpname,
+ NULL);
+
g_free (tmpname);
gboolean writestash;
- writestash = gitg_repository_run_commandv (repository, runner, NULL,
- "read-tree", "-m", tree, NULL) &&
- gitg_repository_run_commandv (repository, runner, NULL,
- "add", "-u", NULL) &&
- gitg_repository_run_commandv (repository, runner, NULL,
- "write-tree", NULL);
+ writestash = gitg_shell_run (shell, cmd_read_tree, NULL) &&
+ gitg_shell_run (shell, cmd_add, NULL) &&
+ gitg_shell_run (shell, cmd_write_tree, NULL);
g_file_delete (customindex, NULL, NULL);
g_object_unref (customindex);
- gitg_runner_set_environment (runner, NULL);
-
if (!writestash)
{
ret = FALSE;
@@ -842,10 +926,23 @@ stash_changes_real (GitgWindow *window, gchar **ref, gboolean storeref)
gchar *stashtree = g_strndup (buffer->str, buffer->len);
gchar *reason = g_strconcat ("gitg auto stash: ", msg, NULL);
- gitg_repository_run_command_with_inputv (repository, runner, reason, NULL,
- "commit-tree", stashtree,
- "-p", head,
- "-p", commit, NULL);
+ inp = g_memory_input_stream_new_from_data (reason, -1, NULL);
+ gitg_io_set_input (GITG_IO (shell), inp);
+ g_object_unref (inp);
+
+ gitg_shell_run (shell,
+ gitg_command_newv (repository,
+ "commit-tree",
+ stashtree,
+ "-p",
+ head,
+ "-p",
+ commit,
+ NULL),
+ NULL);
+
+ gitg_io_set_input (GITG_IO (shell), NULL);
+
g_free (stashtree);
if (buffer->len == 0)
@@ -887,19 +984,30 @@ stash_changes_real (GitgWindow *window, gchar **ref, gboolean storeref)
g_free (path);
- gitg_repository_run_commandv (repository, runner, NULL,
- "update-ref", "-m", reason,
- "refs/stash", rref, NULL);
+ gitg_shell_run (shell,
+ gitg_command_newv (repository,
+ "update-ref",
+ "-m",
+ reason,
+ "refs/stash",
+ rref,
+ NULL),
+ NULL);
g_free (rref);
- gitg_repository_run_commandv (repository, runner, NULL,
- "reset", "--hard", NULL);
+ gitg_shell_run (shell,
+ gitg_command_newv (repository,
+ "reset",
+ "--hard",
+ NULL),
+ NULL);
+
ret = TRUE;
cleanup:
g_string_free (buffer, TRUE);
- g_object_unref (runner);
+ g_object_unref (shell);
g_free (commit);
g_free (tree);
g_free (head);
@@ -938,14 +1046,11 @@ checkout_local_branch_real (GitgWindow *window, GitgRef *ref)
{
GitgRepository *repository = gitg_window_get_repository (window);
- if (!gitg_repository_commandv (repository, NULL, "checkout", gitg_ref_get_shortname (ref), NULL))
- {
- return FALSE;
- }
- else
- {
- return TRUE;
- }
+ return gitg_shell_run_sync (gitg_command_newv (repository,
+ "checkout",
+ gitg_ref_get_shortname (ref),
+ NULL),
+ NULL);
}
static gboolean
@@ -990,14 +1095,14 @@ checkout_remote_branch (GitgWindow *window,
gchar const *local = gitg_ref_get_local_name (ref);
gboolean ret;
- if (!gitg_repository_commandv (repository,
- NULL,
- "checkout",
- "--track",
- "-b",
- local,
- name,
- NULL))
+ if (!gitg_shell_run_sync (gitg_command_newv (repository,
+ "checkout",
+ "--track",
+ "-b",
+ local,
+ name,
+ NULL),
+ NULL))
{
message_dialog (window,
GTK_MESSAGE_ERROR,
@@ -1030,13 +1135,13 @@ checkout_tag (GitgWindow *window,
gchar const *name = gitg_ref_get_shortname (ref);
gboolean ret;
- if (!gitg_repository_commandv (repository,
- NULL,
- "checkout",
- "-b",
- name,
- name,
- NULL))
+ if (!gitg_shell_run_sync (gitg_command_newv (repository,
+ "checkout",
+ "-b",
+ name,
+ name,
+ NULL),
+ NULL))
{
message_dialog (window,
GTK_MESSAGE_ERROR,
@@ -1139,14 +1244,14 @@ on_merge_rebase_result (GitgWindow *window,
}
message_dialog (window,
- GTK_MESSAGE_ERROR,
- message,
- NULL,
- NULL,
- gitg_ref_get_ref_type (info->source) == GITG_REF_TYPE_BRANCH ? _ ("local") : _ ("remote"),
- gitg_ref_get_shortname (info->source),
- gitg_ref_get_ref_type (info->dest) == GITG_REF_TYPE_BRANCH ? _ ("local") : _ ("remote"),
- gitg_ref_get_shortname (info->dest));
+ GTK_MESSAGE_ERROR,
+ message,
+ NULL,
+ NULL,
+ gitg_ref_get_ref_type (info->source) == GITG_REF_TYPE_BRANCH ? _ ("local") : _ ("remote"),
+ gitg_ref_get_shortname (info->source),
+ gitg_ref_get_ref_type (info->dest) == GITG_REF_TYPE_BRANCH ? _ ("local") : _ ("remote"),
+ gitg_ref_get_shortname (info->dest));
}
else if (progress == GITG_PROGRESS_SUCCESS)
{
@@ -1159,32 +1264,43 @@ on_merge_rebase_result (GitgWindow *window,
if (info->stashcommit)
{
- gitg_repository_commandv (repository, NULL,
- "update-ref", "-m", "gitg autosave stash",
- "refs/stash", info->stashcommit, NULL);
+ gitg_shell_run_sync (gitg_command_newv (repository,
+ "update-ref",
+ "-m",
+ "gitg autosave stash",
+ "refs/stash",
+ info->stashcommit,
+ NULL),
+ NULL);
+
message = _ ("The stashed changes have been stored to be reapplied manually");
}
message_dialog (window,
- GTK_MESSAGE_ERROR,
- _ ("Failed to checkout previously checked out branch"),
- message,
- NULL);
+ GTK_MESSAGE_ERROR,
+ _ ("Failed to checkout previously checked out branch"),
+ message,
+ NULL);
}
else if (info->stashcommit)
{
// Reapply stash
- if (!gitg_repository_commandv (gitg_window_get_repository (window),
- NULL,
- "stash",
- "apply",
- "--index",
- info->stashcommit,
- NULL))
+ if (!gitg_shell_run_sync (gitg_command_newv (gitg_window_get_repository (window),
+ "stash",
+ "apply",
+ "--index",
+ info->stashcommit,
+ NULL),
+ NULL))
{
- gitg_repository_commandv (repository, NULL,
- "update-ref", "-m", "gitg autosave stash",
- "refs/stash", info->stashcommit, NULL);
+ gitg_shell_run_sync (gitg_command_newv (repository,
+ "update-ref",
+ "-m",
+ "gitg autosave stash",
+ "refs/stash",
+ info->stashcommit,
+ NULL),
+ NULL);
message_dialog (window,
GTK_MESSAGE_ERROR,
@@ -1200,7 +1316,7 @@ on_merge_rebase_result (GitgWindow *window,
ref_info_free (info);
}
-GitgRunner *
+GitgShell *
gitg_branch_actions_merge (GitgWindow *window,
GitgRef *source,
GitgRef *dest)
@@ -1238,7 +1354,11 @@ gitg_branch_actions_merge (GitgWindow *window,
GitgRef *head = gitg_repository_get_current_working_ref (repository);
// First checkout the correct branch on which to merge, e.g. dest
- if (!gitg_repository_commandv (repository, NULL, "checkout", gitg_ref_get_shortname (dest), NULL))
+ if (!gitg_shell_run_sync (gitg_command_newv (repository,
+ "checkout",
+ gitg_ref_get_shortname (dest),
+ NULL),
+ NULL))
{
g_free (stashcommit);
@@ -1257,7 +1377,7 @@ gitg_branch_actions_merge (GitgWindow *window,
gitg_ref_get_ref_type (dest) == GITG_REF_TYPE_BRANCH ? _ ("local") : _ ("remote"),
gitg_ref_get_shortname (dest));
- GitgRunner *ret;
+ GitgShell *ret;
RefInfo *info = ref_info_new (source, dest);
info->stashcommit = stashcommit;
info->head = gitg_ref_copy (head);
@@ -1277,7 +1397,7 @@ gitg_branch_actions_merge (GitgWindow *window,
return ret;
}
-GitgRunner *
+GitgShell *
gitg_branch_actions_rebase (GitgWindow *window,
GitgRef *source,
GitgRef *dest)
@@ -1340,7 +1460,7 @@ gitg_branch_actions_rebase (GitgWindow *window,
gitg_ref_get_ref_type (dest) == GITG_REF_TYPE_BRANCH ? _ ("local") : _ ("remote"),
gitg_ref_get_shortname (dest));
- GitgRunner *ret;
+ GitgShell *ret;
RefInfo *info = ref_info_new (source, dest);
info->stashcommit = stashcommit;
info->head = gitg_ref_copy (gitg_repository_get_current_working_ref (repository));
@@ -1387,7 +1507,7 @@ on_push_result (GitgWindow *window,
ref_info_free (info);
}
-GitgRunner *
+GitgShell *
gitg_branch_actions_push (GitgWindow *window,
GitgRef *source,
GitgRef *dest)
@@ -1423,7 +1543,7 @@ gitg_branch_actions_push (GitgWindow *window,
gitg_ref_get_shortname (source),
gitg_ref_get_shortname (dest));
- GitgRunner *ret;
+ GitgShell *ret;
RefInfo *info = ref_info_new (source, dest);
ret = run_progress (window,
@@ -1442,7 +1562,7 @@ gitg_branch_actions_push (GitgWindow *window,
return ret;
}
-GitgRunner *
+GitgShell *
gitg_branch_actions_push_remote (GitgWindow *window,
GitgRef *source,
gchar const *remote,
@@ -1475,7 +1595,7 @@ gitg_branch_actions_push_remote (GitgWindow *window,
gitg_ref_get_shortname (source),
remote, branch);
- GitgRunner *ret;
+ GitgShell *ret;
gchar *rr = g_strconcat ("refs/remotes/", remote, "/", branch, NULL);
GitgRef *rmref = gitg_ref_new ("0000000000000000000000000000000000000000", rr);
g_free (rr);
@@ -1546,13 +1666,13 @@ gitg_branch_actions_apply_stash (GitgWindow *window,
gchar *sha1 = gitg_hash_hash_to_sha1_new (gitg_ref_get_hash (stash));
gboolean ret;
- if (!gitg_repository_commandv (repository,
- NULL,
- "stash",
- "apply",
- "--index",
- sha1,
- NULL))
+ if (!gitg_shell_run_sync (gitg_command_newv (repository,
+ "stash",
+ "apply",
+ "--index",
+ sha1,
+ NULL),
+ NULL))
{
message = g_strdup_printf (_ ("The stash could not be applied to local branch <%s>"),
gitg_ref_get_shortname (branch));
@@ -1590,12 +1710,12 @@ gitg_branch_actions_create (GitgWindow *window, gchar const *sha1, gchar const *
repository = gitg_window_get_repository (window);
- result = gitg_repository_commandv (repository,
- NULL,
- "branch",
- name,
- sha1,
- NULL);
+ result = gitg_shell_run_sync (gitg_command_newv (repository,
+ "branch",
+ name,
+ sha1,
+ NULL),
+ NULL);
if (!result)
{
@@ -1631,24 +1751,24 @@ gitg_branch_actions_tag (GitgWindow *window, gchar const *sha1, gchar const *nam
if (message != NULL && message[0] != '\0')
{
- result = gitg_repository_commandv (repository,
- NULL,
- "tag",
- "-m",
- message,
- sign ? "-s" : "-a",
- name,
- sha1,
- NULL);
+ result = gitg_shell_run_sync (gitg_command_newv (repository,
+ "tag",
+ "-m",
+ message,
+ sign ? "-s" : "-a",
+ name,
+ sha1,
+ NULL),
+ NULL);
}
else
{
- result = gitg_repository_commandv (repository,
- NULL,
- "tag",
- name,
- sha1,
- NULL);
+ result = gitg_shell_run_sync (gitg_command_newv (repository,
+ "tag",
+ name,
+ sha1,
+ NULL),
+ NULL);
}
if (!result)
@@ -1737,9 +1857,14 @@ on_cherry_pick_result (GitgWindow *window,
if (info->stashcommit)
{
- gitg_repository_commandv (repository, NULL,
- "update-ref", "-m", "gitg autosave stash",
- "refs/stash", info->stashcommit, NULL);
+ gitg_shell_run_sync (gitg_command_newv (repository,
+ "update-ref",
+ "-m",
+ "gitg autosave stash",
+ "refs/stash",
+ info->stashcommit,
+ NULL),
+ NULL);
message = _ ("The stashed changes have been stored to be reapplied manually");
}
@@ -1753,17 +1878,22 @@ on_cherry_pick_result (GitgWindow *window,
else if (info->stashcommit)
{
// Reapply stash
- if (!gitg_repository_commandv (gitg_window_get_repository (window),
- NULL,
- "stash",
- "apply",
- "--index",
- info->stashcommit,
- NULL))
+ if (!gitg_shell_run_sync (gitg_command_newv (gitg_window_get_repository (window),
+ "stash",
+ "apply",
+ "--index",
+ info->stashcommit,
+ NULL),
+ NULL))
{
- gitg_repository_commandv (repository, NULL,
- "update-ref", "-m", "gitg autosave stash",
- "refs/stash", info->stashcommit, NULL);
+ gitg_shell_run_sync (gitg_command_newv (repository,
+ "update-ref",
+ "-m",
+ "gitg autosave stash",
+ "refs/stash",
+ info->stashcommit,
+ NULL),
+ NULL);
message_dialog (window,
GTK_MESSAGE_ERROR,
@@ -1779,7 +1909,7 @@ on_cherry_pick_result (GitgWindow *window,
cherry_pick_info_free (info);
}
-GitgRunner *
+GitgShell *
gitg_branch_actions_cherry_pick (GitgWindow *window,
GitgRevision *revision,
GitgRef *dest)
@@ -1812,11 +1942,11 @@ gitg_branch_actions_cherry_pick (GitgWindow *window,
GitgRef *head = gitg_repository_get_current_working_ref (repository);
// First checkout the correct branch on which to cherry-pick
- if (!gitg_repository_commandv (repository,
- NULL,
- "checkout",
- gitg_ref_get_shortname (dest),
- NULL))
+ if (!gitg_shell_run_sync (gitg_command_newv (repository,
+ "checkout",
+ gitg_ref_get_shortname (dest),
+ NULL),
+ NULL))
{
g_free (stashcommit);
@@ -1833,7 +1963,7 @@ gitg_branch_actions_cherry_pick (GitgWindow *window,
message = g_strdup_printf (_ ("Cherry-picking on <%s>"),
gitg_ref_get_shortname (dest));
- GitgRunner *ret;
+ GitgShell *ret;
CherryPickInfo *info = cherry_pick_info_new (revision, dest);
@@ -1908,7 +2038,7 @@ on_format_patch_result (GitgWindow *window,
}
static void
-on_format_patch_update (GitgRunner *runner,
+on_format_patch_update (GitgShell *shell,
gchar **lines,
FormatPatchInfo *info)
{
@@ -1920,7 +2050,7 @@ on_format_patch_update (GitgRunner *runner,
}
}
-GitgRunner *
+GitgShell *
gitg_branch_actions_format_patch (GitgWindow *window,
GitgRevision *revision,
gchar const *destination)
@@ -1929,7 +2059,7 @@ gitg_branch_actions_format_patch (GitgWindow *window,
g_return_val_if_fail (revision != NULL, NULL);
g_return_val_if_fail (destination != NULL, NULL);
- GitgRunner *ret;
+ GitgShell *ret;
GFile *file = g_file_new_for_uri (destination);
GFileOutputStream *stream = g_file_replace (file,
diff --git a/gitg/gitg-branch-actions.h b/gitg/gitg-branch-actions.h
index 58b7f18..88fac6a 100644
--- a/gitg/gitg-branch-actions.h
+++ b/gitg/gitg-branch-actions.h
@@ -24,28 +24,28 @@
#define __GITG_BRANCH_ACTIONS_H__
#include <libgitg/gitg-ref.h>
-#include "gitg-window.h"
+#include <gitg/gitg-window.h>
G_BEGIN_DECLS
gboolean gitg_branch_actions_create (GitgWindow *window, gchar const *sha1, gchar const *name);
-GitgRunner *gitg_branch_actions_remove (GitgWindow *window, GitgRef *ref);
-GitgRunner *gitg_branch_actions_rename (GitgWindow *window, GitgRef *ref);
+GitgShell *gitg_branch_actions_remove (GitgWindow *window, GitgRef *ref);
+GitgShell *gitg_branch_actions_rename (GitgWindow *window, GitgRef *ref);
gboolean gitg_branch_actions_checkout (GitgWindow *window, GitgRef *ref);
-GitgRunner *gitg_branch_actions_merge (GitgWindow *window, GitgRef *source, GitgRef *dest);
-GitgRunner *gitg_branch_actions_rebase (GitgWindow *window, GitgRef *source, GitgRef *dest);
+GitgShell *gitg_branch_actions_merge (GitgWindow *window, GitgRef *source, GitgRef *dest);
+GitgShell *gitg_branch_actions_rebase (GitgWindow *window, GitgRef *source, GitgRef *dest);
-GitgRunner *gitg_branch_actions_push (GitgWindow *window, GitgRef *source, GitgRef *dest);
-GitgRunner *gitg_branch_actions_push_remote (GitgWindow *window, GitgRef *source, gchar const *remote, gchar const *branch);
+GitgShell *gitg_branch_actions_push (GitgWindow *window, GitgRef *source, GitgRef *dest);
+GitgShell *gitg_branch_actions_push_remote (GitgWindow *window, GitgRef *source, gchar const *remote, gchar const *branch);
gboolean gitg_branch_actions_apply_stash (GitgWindow *window, GitgRef *stash, GitgRef *branch);
gboolean gitg_branch_actions_tag (GitgWindow *window, gchar const *sha1, gchar const *name, gchar const *message, gboolean sign);
-GitgRunner *gitg_branch_actions_cherry_pick (GitgWindow *window, GitgRevision *revision, GitgRef *dest);
+GitgShell *gitg_branch_actions_cherry_pick (GitgWindow *window, GitgRevision *revision, GitgRef *dest);
-GitgRunner *gitg_branch_actions_format_patch (GitgWindow *window, GitgRevision *revision, gchar const *destination);
+GitgShell *gitg_branch_actions_format_patch (GitgWindow *window, GitgRevision *revision, gchar const *destination);
G_END_DECLS
diff --git a/gitg/gitg-commit-view.c b/gitg/gitg-commit-view.c
index 38bc044..8b844a9 100644
--- a/gitg/gitg-commit-view.c
+++ b/gitg/gitg-commit-view.c
@@ -26,6 +26,7 @@
#include <glib/gi18n.h>
#include <string.h>
#include <libgitg/gitg-commit.h>
+#include <libgitg/gitg-shell.h>
#include "gitg-commit-view.h"
#include "gitg-diff-view.h"
@@ -78,7 +79,7 @@ struct _GitgCommitViewPrivate
GtkHScale *hscale_context;
gint context_size;
- GitgRunner *runner;
+ GitgShell *shell;
guint update_id;
gboolean is_diff;
@@ -138,11 +139,11 @@ gitg_commit_view_finalize (GObject *object)
if (view->priv->update_id)
{
- g_signal_handler_disconnect (view->priv->runner, view->priv->update_id);
+ g_signal_handler_disconnect (view->priv->shell, view->priv->update_id);
}
- gitg_runner_cancel (view->priv->runner);
- g_object_unref (view->priv->runner);
+ gitg_io_cancel (GITG_IO (view->priv->shell));
+ g_object_unref (view->priv->shell);
g_object_unref (view->priv->ui_manager);
gdk_cursor_unref (view->priv->hand);
@@ -224,7 +225,7 @@ show_binary_information (GitgCommitView *view)
}
static void
-on_changes_update (GitgRunner *runner, gchar **buffer, GitgCommitView *view)
+on_changes_update (GitgShell *shell, gchar **buffer, GitgCommitView *view)
{
gchar *line;
GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW(view->priv->changes_view));
@@ -261,7 +262,7 @@ on_changes_update (GitgRunner *runner, gchar **buffer, GitgCommitView *view)
if (content_type && !gitg_utils_can_display_content_type (content_type))
{
- gitg_runner_cancel (runner);
+ gitg_io_cancel (GITG_IO (shell));
show_binary_information (view);
}
else if (content_type)
@@ -283,7 +284,7 @@ on_changes_update (GitgRunner *runner, gchar **buffer, GitgCommitView *view)
static void
connect_update (GitgCommitView *view)
{
- view->priv->update_id = g_signal_connect (view->priv->runner,
+ view->priv->update_id = g_signal_connect (view->priv->shell,
"update",
G_CALLBACK (on_changes_update),
view);
@@ -384,9 +385,11 @@ check_selection(GtkTreeView *tree_view,
GitgCommitView *view)
{
if (view->priv->update_id)
- g_signal_handler_disconnect(view->priv->runner, view->priv->update_id);
+ {
+ g_signal_handler_disconnect(view->priv->shell, view->priv->update_id);
+ }
- gitg_runner_cancel(view->priv->runner);
+ gitg_io_cancel(GITG_IO (view->priv->shell));
view->priv->update_id = 0;
GtkTextView *tv = GTK_TEXT_VIEW(view->priv->changes_view);
@@ -478,7 +481,7 @@ unstaged_selection_changed (GtkTreeSelection *selection,
view->priv->is_diff = FALSE;
connect_update (view);
- gitg_runner_run_stream (view->priv->runner, stream, NULL);
+ gitg_shell_run_stream (view->priv->shell, stream, NULL);
g_object_unref (stream);
}
}
@@ -487,6 +490,8 @@ unstaged_selection_changed (GtkTreeSelection *selection,
}
else
{
+ gboolean allow_external;
+
set_diff_language (view);
view->priv->is_diff = TRUE;
connect_update (view);
@@ -496,15 +501,22 @@ unstaged_selection_changed (GtkTreeSelection *selection,
gchar ct[10];
g_snprintf (ct, sizeof(ct), "-U%d", view->priv->context_size);
- gitg_repository_run_commandv (view->priv->repository,
- view->priv->runner,
- NULL,
- "diff",
- "--no-color",
- ct,
- "--",
- path,
- NULL);
+ g_object_get (gitg_preferences_get_default (),
+ "diff-external",
+ &allow_external,
+ NULL);
+
+ gitg_shell_run (view->priv->shell,
+ gitg_command_newv (view->priv->repository,
+ "diff",
+ allow_external ? "--ext-diff" : "--no-ext-diff",
+ "--no-color",
+ ct,
+ "--",
+ path,
+ NULL),
+ NULL);
+
g_free (path);
}
@@ -521,7 +533,9 @@ staged_selection_changed (GtkTreeSelection *selection, GitgCommitView *view)
GtkTreeIter iter;
if (!check_selection (view->priv->tree_view_staged, &iter, view))
+ {
return;
+ }
model = gtk_tree_view_get_model (view->priv->tree_view_staged);
unselect_tree_view (view->priv->tree_view_unstaged);
@@ -561,14 +575,15 @@ staged_selection_changed (GtkTreeSelection *selection, GitgCommitView *view)
connect_update (view);
gchar *indexpath = g_strconcat (":0:", path, NULL);
- gitg_repository_run_commandv (view->priv->repository,
- view->priv->runner,
- NULL,
- "show",
- "--encoding=UTF-8",
- "--no-color",
- indexpath,
- NULL);
+ gitg_shell_run (view->priv->shell,
+ gitg_command_newv (view->priv->repository,
+ "show",
+ "--encoding=UTF-8",
+ "--no-color",
+ indexpath,
+ NULL),
+ NULL);
+
g_free (indexpath);
}
@@ -576,6 +591,8 @@ staged_selection_changed (GtkTreeSelection *selection, GitgCommitView *view)
}
else
{
+ gboolean allow_external;
+
view->priv->is_diff = TRUE;
set_diff_language (view);
connect_update (view);
@@ -584,17 +601,24 @@ staged_selection_changed (GtkTreeSelection *selection, GitgCommitView *view)
gchar ct[10];
g_snprintf (ct, sizeof(ct), "-U%d", view->priv->context_size);
- gitg_repository_run_commandv (view->priv->repository,
- view->priv->runner,
- NULL,
- "diff-index",
- ct,
- "--cached",
- "--no-color",
- head,
- "--",
- path,
- NULL);
+ g_object_get (gitg_preferences_get_default (),
+ "diff-external",
+ &allow_external,
+ NULL);
+
+ gitg_shell_run (view->priv->shell,
+ gitg_command_newv (view->priv->repository,
+ "diff-index",
+ allow_external ? "--ext-diff" : "--no-ext-diff",
+ ct,
+ "--cached",
+ "--no-color",
+ head,
+ "--",
+ path,
+ NULL),
+ NULL);
+
g_free(head);
}
@@ -1659,8 +1683,8 @@ gitg_commit_view_init (GitgCommitView *self)
{
self->priv = GITG_COMMIT_VIEW_GET_PRIVATE (self);
- self->priv->runner = gitg_runner_new (10000);
- gitg_runner_set_preserve_line_endings (self->priv->runner, TRUE);
+ self->priv->shell = gitg_shell_new (10000);
+ gitg_shell_set_preserve_line_endings (self->priv->shell, TRUE);
self->priv->hand = gdk_cursor_new (GDK_HAND1);
}
@@ -2174,7 +2198,10 @@ do_revert_changes(GitgCommitView *view)
for (item = files; item; item = g_list_next (item))
{
- ret &= gitg_commit_revert(view->priv->commit, GITG_CHANGED_FILE (item->data), NULL, NULL);
+ ret &= gitg_commit_undo (view->priv->commit,
+ GITG_CHANGED_FILE (item->data),
+ NULL,
+ NULL);
g_object_unref (item->data);
}
@@ -2185,11 +2212,17 @@ do_revert_changes(GitgCommitView *view)
GitgChangedFile *file = g_object_ref(view->priv->current_file);
gchar *hunk = get_hunk_patch(view, &view->priv->context_iter);
- ret = gitg_commit_revert(view->priv->commit, view->priv->current_file, hunk, NULL);
+ ret = gitg_commit_undo (view->priv->commit,
+ view->priv->current_file,
+ hunk,
+ NULL);
g_free(hunk);
if (ret && view->priv->current_file == file)
- gitg_diff_view_remove_hunk(GITG_DIFF_VIEW(view->priv->changes_view), &view->priv->context_iter);
+ {
+ gitg_diff_view_remove_hunk (GITG_DIFF_VIEW(view->priv->changes_view),
+ &view->priv->context_iter);
+ }
g_object_unref(file);
}
diff --git a/gitg/gitg-dnd.c b/gitg/gitg-dnd.c
index b5e41be..e393c1a 100644
--- a/gitg/gitg-dnd.c
+++ b/gitg/gitg-dnd.c
@@ -777,13 +777,14 @@ revision_to_text (GitgRepository *repository,
gchar **lines;
gchar *sha1 = gitg_revision_get_sha1 (revision);
- lines = gitg_repository_command_with_outputv (repository,
- NULL,
- "log",
- "-1",
- "--pretty=format:%h: %s%n%n%b",
- sha1,
- NULL);
+ lines = gitg_shell_run_sync_with_output (gitg_command_newv (repository,
+ "log",
+ "-1",
+ "--pretty=format:%h: %s%n%n%b",
+ sha1,
+ NULL),
+ FALSE,
+ NULL);
remove_trailing_newlines (lines);
gchar *ret = g_strjoinv ("\n", lines);
diff --git a/gitg/gitg-repository-dialog.c b/gitg/gitg-repository-dialog.c
index c1dc6ac..aceebd9 100644
--- a/gitg/gitg-repository-dialog.c
+++ b/gitg/gitg-repository-dialog.c
@@ -24,6 +24,7 @@
#include <stdlib.h>
#include <libgitg/gitg-config.h>
+#include <libgitg/gitg-shell.h>
#include "gitg-repository-dialog.h"
#include "gitg-utils.h"
@@ -100,7 +101,7 @@ G_DEFINE_TYPE (GitgRepositoryDialog, gitg_repository_dialog, GTK_TYPE_DIALOG)
typedef struct
{
GitgRepositoryDialog *dialog;
- GitgRunner *runner;
+ GitgShell *shell;
GtkTreeRowReference *reference;
#ifdef BUILD_SPINNER
@@ -149,7 +150,7 @@ fetch_cleanup (FetchInfo *info)
#endif
gtk_tree_row_reference_free (info->reference);
- g_object_unref (info->runner);
+ g_object_unref (info->shell);
g_slice_free (FetchInfo, info);
}
@@ -174,7 +175,7 @@ gitg_repository_dialog_finalize (GObject *object)
for (item = copy; item; item = g_list_next (item))
{
- gitg_runner_cancel (((FetchInfo *)item->data)->runner);
+ gitg_io_cancel (GITG_IO (((FetchInfo *)item->data)->shell));
}
g_list_free (copy);
@@ -341,7 +342,7 @@ pulse_row (FetchInfo *info)
#endif
static void
-on_fetch_begin_loading (GitgRunner *runner, FetchInfo *info)
+on_fetch_begin_loading (GitgShell *shell, FetchInfo *info)
{
GtkTreeIter iter;
GtkTreePath *path = gtk_tree_row_reference_get_path (info->reference);
@@ -387,7 +388,7 @@ on_fetch_begin_loading (GitgRunner *runner, FetchInfo *info)
}
static void
-on_fetch_end_loading (GitgRunner *runner, gboolean cancelled, FetchInfo *info)
+on_fetch_end_loading (GitgShell *shell, gboolean cancelled, FetchInfo *info)
{
if (cancelled || !gtk_tree_row_reference_valid (info->reference))
{
@@ -406,7 +407,7 @@ on_fetch_end_loading (GitgRunner *runner, gboolean cancelled, FetchInfo *info)
static void
fetch_remote (GitgRepositoryDialog *dialog, GtkTreeIter *iter)
{
- GitgRunner *runner = gitg_runner_new (1000);
+ GitgShell *shell = gitg_shell_new (1000);
FetchInfo *info = g_slice_new0 (FetchInfo);
GtkTreeModel *model = GTK_TREE_MODEL (dialog->priv->list_store_remotes);
@@ -414,17 +415,17 @@ fetch_remote (GitgRepositoryDialog *dialog, GtkTreeIter *iter)
info->dialog = dialog;
info->reference = gtk_tree_row_reference_new (model, path);
- info->runner = runner;
+ info->shell = shell;
gtk_tree_path_free (path);
- g_signal_connect (runner,
- "begin-loading",
+ g_signal_connect (shell,
+ "begin",
G_CALLBACK (on_fetch_begin_loading),
info);
- g_signal_connect (runner,
- "end-loading",
+ g_signal_connect (shell,
+ "end",
G_CALLBACK (on_fetch_end_loading),
info);
@@ -433,12 +434,12 @@ fetch_remote (GitgRepositoryDialog *dialog, GtkTreeIter *iter)
gchar *name;
gtk_tree_model_get (model, iter, COLUMN_NAME, &name, -1);
- gitg_repository_run_commandv (dialog->priv->repository,
- runner,
- NULL,
- "fetch",
- name,
- NULL);
+ gitg_shell_run (shell,
+ gitg_command_newv (dialog->priv->repository,
+ "fetch",
+ name,
+ NULL),
+ NULL);
g_free (name);
}
@@ -684,7 +685,7 @@ fetch_remote_cancel (GitgRepositoryDialog *dialog,
if (equal)
{
- gitg_runner_cancel (info->runner);
+ gitg_io_cancel (GITG_IO (info->shell));
break;
}
}
@@ -736,12 +737,12 @@ on_button_fetch_remote_clicked (GtkButton *button,
static gboolean
remove_remote (GitgRepositoryDialog *dialog, gchar const *name)
{
- return gitg_repository_commandv (dialog->priv->repository,
- NULL,
- "remote",
- "rm",
- name,
- NULL);
+ return gitg_shell_run_sync (gitg_command_newv (dialog->priv->repository,
+ "remote",
+ "rm",
+ name,
+ NULL),
+ NULL);
}
void
@@ -828,7 +829,13 @@ on_button_add_remote_clicked (GtkButton *button,
gchar *name = g_strdup_printf ("remote%d", num + 1);
gchar const url[] = "git://example.com/repository.git";
- if (gitg_repository_commandv (dialog->priv->repository, NULL, "remote", "add", name, url, NULL))
+ if (gitg_shell_run_sync (gitg_command_newv (dialog->priv->repository,
+ "remote",
+ "add",
+ name,
+ url,
+ NULL),
+ NULL))
{
GtkTreeIter iter;
GtkTreePath *path;
@@ -901,7 +908,13 @@ on_remote_name_edited (GtkCellRendererText *renderer,
COLUMN_URL, &url,
-1);
- if (gitg_repository_commandv (dialog->priv->repository, NULL, "remote", "add", new_text, url, NULL))
+ if (gitg_shell_run_sync (gitg_command_newv (dialog->priv->repository,
+ "remote",
+ "add",
+ new_text,
+ url,
+ NULL),
+ NULL))
{
remove_remote (dialog, oldname);
diff --git a/gitg/gitg-revision-changes-panel.c b/gitg/gitg-revision-changes-panel.c
index bf58635..0aef963 100644
--- a/gitg/gitg-revision-changes-panel.c
+++ b/gitg/gitg-revision-changes-panel.c
@@ -6,12 +6,14 @@
#include <string.h>
#include <libgitg/gitg-repository.h>
#include <libgitg/gitg-revision.h>
-#include <libgitg/gitg-runner.h>
+#include <libgitg/gitg-shell.h>
#include <libgitg/gitg-hash.h>
#include "gitg-diff-view.h"
#include "gitg-utils.h"
+#include "gitg-preferences.h"
#include <glib/gi18n.h>
+
#include "gitg-revision-panel.h"
#include "gitg-activatable.h"
@@ -26,8 +28,8 @@ struct _GitgRevisionChangesPanelPrivate
GtkTreeView *diff_files;
GtkListStore *list_store_diff_files;
- GitgRunner *diff_runner;
- GitgRunner *diff_files_runner;
+ GitgShell *diff_shell;
+ GitgShell *diff_files_shell;
GitgRepository *repository;
GitgRevision *revision;
@@ -520,16 +522,16 @@ gitg_revision_changes_panel_dispose (GObject *object)
set_revision (changes_panel, NULL, NULL);
- if (changes_panel->priv->diff_files_runner)
+ if (changes_panel->priv->diff_files_shell)
{
- g_object_unref (changes_panel->priv->diff_files_runner);
- changes_panel->priv->diff_files_runner = NULL;
+ g_object_unref (changes_panel->priv->diff_files_shell);
+ changes_panel->priv->diff_files_shell = NULL;
}
- if (changes_panel->priv->diff_files_runner)
+ if (changes_panel->priv->diff_files_shell)
{
- g_object_unref (changes_panel->priv->diff_runner);
- changes_panel->priv->diff_runner = NULL;
+ g_object_unref (changes_panel->priv->diff_shell);
+ changes_panel->priv->diff_shell = NULL;
}
if (changes_panel->priv->builder)
@@ -564,8 +566,8 @@ reload_diff (GitgRevisionChangesPanel *changes_panel)
GtkTreeSelection *selection;
// First cancel a possibly still running diff
- gitg_runner_cancel (changes_panel->priv->diff_runner);
- gitg_runner_cancel (changes_panel->priv->diff_files_runner);
+ gitg_io_cancel (GITG_IO (changes_panel->priv->diff_shell));
+ gitg_io_cancel (GITG_IO (changes_panel->priv->diff_files_shell));
free_cached_headers (changes_panel);
@@ -592,45 +594,54 @@ reload_diff (GitgRevisionChangesPanel *changes_panel)
}
gchar sign = gitg_revision_get_sign (changes_panel->priv->revision);
+ gboolean allow_external;
+
+ g_object_get (gitg_preferences_get_default (),
+ "diff-external",
+ &allow_external,
+ NULL);
switch (sign)
{
case 't':
- gitg_repository_run_commandv (changes_panel->priv->repository,
- changes_panel->priv->diff_runner,
- NULL,
- "diff",
- "--cached",
- "-M",
- "--pretty=format:",
- "--encoding=UTF-8",
- "--no-color",
- NULL);
+ gitg_shell_run (changes_panel->priv->diff_shell,
+ gitg_command_newv (changes_panel->priv->repository,
+ "diff",
+ allow_external ? "--ext-diff" : "--no-ext-diff",
+ "--cached",
+ "-M",
+ "--pretty=format:",
+ "--encoding=UTF-8",
+ "--no-color",
+ NULL),
+ NULL);
break;
case 'u':
- gitg_repository_run_commandv (changes_panel->priv->repository,
- changes_panel->priv->diff_runner,
- NULL,
- "diff",
- "-M",
- "--pretty=format:",
- "--encoding=UTF-8",
- "--no-color",
- NULL);
+ gitg_shell_run (changes_panel->priv->diff_shell,
+ gitg_command_newv (changes_panel->priv->repository,
+ "diff",
+ allow_external ? "--ext-diff" : "--no-ext-diff",
+ "-M",
+ "--pretty=format:",
+ "--encoding=UTF-8",
+ "--no-color",
+ NULL),
+ NULL);
break;
default:
{
gchar *hash = gitg_revision_get_sha1 (changes_panel->priv->revision);
- gitg_repository_run_commandv (changes_panel->priv->repository,
- changes_panel->priv->diff_runner,
- NULL,
- "show",
- "-M",
- "--pretty=format:",
- "--encoding=UTF-8",
- "--no-color",
- hash,
- NULL);
+
+ gitg_shell_run (changes_panel->priv->diff_shell,
+ gitg_command_newv (changes_panel->priv->repository,
+ "show",
+ "-M",
+ "--pretty=format:",
+ "--encoding=UTF-8",
+ "--no-color",
+ hash,
+ NULL),
+ NULL);
g_free (hash);
}
@@ -649,14 +660,14 @@ set_revision (GitgRevisionChangesPanel *changes_panel,
return;
}
- if (changes_panel->priv->diff_runner)
+ if (changes_panel->priv->diff_shell)
{
- gitg_runner_cancel (changes_panel->priv->diff_runner);
+ gitg_io_cancel (GITG_IO (changes_panel->priv->diff_shell));
}
- if (changes_panel->priv->diff_files_runner)
+ if (changes_panel->priv->diff_files_shell)
{
- gitg_runner_cancel (changes_panel->priv->diff_files_runner);
+ gitg_io_cancel (GITG_IO (changes_panel->priv->diff_files_shell));
}
if (changes_panel->priv->repository)
@@ -691,7 +702,7 @@ set_revision (GitgRevisionChangesPanel *changes_panel,
}
static void
-on_diff_files_begin_loading (GitgRunner *runner,
+on_diff_files_begin_loading (GitgShell *shell,
GitgRevisionChangesPanel *self)
{
GdkCursor *cursor = gdk_cursor_new (GDK_WATCH);
@@ -703,7 +714,7 @@ on_diff_files_begin_loading (GitgRunner *runner,
}
static void
-on_diff_files_end_loading (GitgRunner *runner,
+on_diff_files_end_loading (GitgShell *shell,
gboolean cancelled,
GitgRevisionChangesPanel *self)
{
@@ -766,7 +777,7 @@ add_diff_file (GitgRevisionChangesPanel *view,
}
static void
-on_diff_files_update (GitgRunner *runner,
+on_diff_files_update (GitgShell *shell,
gchar **buffer,
GitgRevisionChangesPanel *self)
{
@@ -808,7 +819,7 @@ on_diff_files_update (GitgRunner *runner,
}
static void
-on_diff_begin_loading (GitgRunner *runner,
+on_diff_begin_loading (GitgShell *shell,
GitgRevisionChangesPanel *self)
{
GdkCursor *cursor = gdk_cursor_new (GDK_WATCH);
@@ -818,7 +829,7 @@ on_diff_begin_loading (GitgRunner *runner,
}
static void
-on_diff_end_loading (GitgRunner *runner,
+on_diff_end_loading (GitgShell *shell,
gboolean cancelled,
GitgRevisionChangesPanel *self)
{
@@ -831,6 +842,12 @@ on_diff_end_loading (GitgRunner *runner,
}
gchar sign = gitg_revision_get_sign (self->priv->revision);
+ gboolean allow_external;
+
+ g_object_get (gitg_preferences_get_default (),
+ "diff-external",
+ &allow_external,
+ NULL);
if (sign == 't' || sign == 'u')
{
@@ -840,38 +857,39 @@ on_diff_end_loading (GitgRunner *runner,
if (sign == 't')
cached = "--cached";
- gitg_repository_run_commandv (self->priv->repository,
- self->priv->diff_files_runner,
- NULL,
- "diff-index",
- "--raw",
- "-M",
- "--abbrev=40",
- head,
- cached,
- NULL);
+ gitg_shell_run (self->priv->diff_files_shell,
+ gitg_command_newv (self->priv->repository,
+ "diff-index",
+ allow_external ? "--ext-diff" : "--no-ext-diff",
+ "--raw",
+ "-M",
+ "--abbrev=40",
+ head,
+ cached,
+ NULL),
+ NULL);
g_free (head);
}
else
{
gchar *sha = gitg_revision_get_sha1 (self->priv->revision);
- gitg_repository_run_commandv (self->priv->repository,
- self->priv->diff_files_runner,
- NULL,
- "show",
- "--encoding=UTF-8",
- "--raw",
- "-M",
- "--pretty=format:",
- "--abbrev=40",
- sha,
- NULL);
+ gitg_shell_run (self->priv->diff_files_shell,
+ gitg_command_newv (self->priv->repository,
+ "show",
+ "--encoding=UTF-8",
+ "--raw",
+ "-M",
+ "--pretty=format:",
+ "--abbrev=40",
+ sha,
+ NULL),
+ NULL);
g_free (sha);
}
}
static void
-on_diff_update (GitgRunner *runner,
+on_diff_update (GitgShell *shell,
gchar **buffer,
GitgRevisionChangesPanel *self)
{
@@ -893,37 +911,37 @@ gitg_revision_changes_panel_init (GitgRevisionChangesPanel *self)
{
self->priv = GITG_REVISION_CHANGES_PANEL_GET_PRIVATE (self);
- self->priv->diff_runner = gitg_runner_new (2000);
+ self->priv->diff_shell = gitg_shell_new (2000);
- g_signal_connect (self->priv->diff_runner,
- "begin-loading",
+ g_signal_connect (self->priv->diff_shell,
+ "begin",
G_CALLBACK (on_diff_begin_loading),
self);
- g_signal_connect (self->priv->diff_runner,
+ g_signal_connect (self->priv->diff_shell,
"update",
G_CALLBACK (on_diff_update),
self);
- g_signal_connect (self->priv->diff_runner,
- "end-loading",
+ g_signal_connect (self->priv->diff_shell,
+ "end",
G_CALLBACK (on_diff_end_loading),
self);
- self->priv->diff_files_runner = gitg_runner_new (2000);
+ self->priv->diff_files_shell = gitg_shell_new (2000);
- g_signal_connect (self->priv->diff_files_runner,
- "begin-loading",
+ g_signal_connect (self->priv->diff_files_shell,
+ "begin",
G_CALLBACK(on_diff_files_begin_loading),
self);
- g_signal_connect (self->priv->diff_files_runner,
+ g_signal_connect (self->priv->diff_files_shell,
"update",
G_CALLBACK(on_diff_files_update),
self);
- g_signal_connect (self->priv->diff_files_runner,
- "end-loading",
+ g_signal_connect (self->priv->diff_files_shell,
+ "end",
G_CALLBACK(on_diff_files_end_loading),
self);
}
diff --git a/gitg/gitg-revision-details-panel.c b/gitg/gitg-revision-details-panel.c
index 67c17d7..f879131 100644
--- a/gitg/gitg-revision-details-panel.c
+++ b/gitg/gitg-revision-details-panel.c
@@ -54,7 +54,7 @@ struct _GitgRevisionDetailsPanelPrivate
GitgRepository *repository;
GitgRevision *revision;
- GitgRunner *runner;
+ GitgShell *shell;
gboolean in_stat;
GSList *stats;
@@ -202,12 +202,12 @@ gitg_revision_details_panel_dispose (GObject *object)
panel->priv->builder = NULL;
}
- if (panel->priv->runner)
+ if (panel->priv->shell)
{
- gitg_runner_cancel (panel->priv->runner);
- g_object_unref (panel->priv->runner);
+ gitg_io_cancel (GITG_IO (panel->priv->shell));
+ g_object_unref (panel->priv->shell);
- panel->priv->runner = NULL;
+ panel->priv->shell = NULL;
}
G_OBJECT_CLASS (gitg_revision_details_panel_parent_class)->dispose (object);
@@ -224,8 +224,8 @@ gitg_revision_details_panel_class_init (GitgRevisionDetailsPanelClass *klass)
}
static void
-on_runner_begin (GitgRunner *runner,
- GitgRevisionDetailsPanel *panel)
+on_shell_begin (GitgShell *shell,
+ GitgRevisionDetailsPanel *panel)
{
GdkCursor *cursor;
@@ -363,9 +363,9 @@ make_stats_table (GitgRevisionDetailsPanel *panel)
}
static void
-on_runner_end (GitgRunner *runner,
- gboolean cancelled,
- GitgRevisionDetailsPanel *panel)
+on_shell_end (GitgShell *shell,
+ gboolean cancelled,
+ GitgRevisionDetailsPanel *panel)
{
gdk_window_set_cursor (gtk_widget_get_window (GTK_WIDGET (panel->priv->text_view)),
NULL);
@@ -432,9 +432,9 @@ add_stat (GitgRevisionDetailsPanel *panel,
}
static void
-on_runner_update (GitgRunner *runner,
- gchar **lines,
- GitgRevisionDetailsPanel *panel)
+on_shell_update (GitgShell *shell,
+ gchar **lines,
+ GitgRevisionDetailsPanel *panel)
{
GtkTextBuffer *buffer;
GtkTextIter end;
@@ -476,21 +476,21 @@ gitg_revision_details_panel_init (GitgRevisionDetailsPanel *self)
{
self->priv = GITG_REVISION_DETAILS_PANEL_GET_PRIVATE(self);
- self->priv->runner = gitg_runner_new (1000);
+ self->priv->shell = gitg_shell_new (1000);
- g_signal_connect (self->priv->runner,
- "begin-loading",
- G_CALLBACK (on_runner_begin),
+ g_signal_connect (self->priv->shell,
+ "begin",
+ G_CALLBACK (on_shell_begin),
self);
- g_signal_connect (self->priv->runner,
- "end-loading",
- G_CALLBACK (on_runner_end),
+ g_signal_connect (self->priv->shell,
+ "end",
+ G_CALLBACK (on_shell_end),
self);
- g_signal_connect (self->priv->runner,
+ g_signal_connect (self->priv->shell,
"update",
- G_CALLBACK (on_runner_update),
+ G_CALLBACK (on_shell_update),
self);
}
@@ -644,7 +644,7 @@ update_details (GitgRevisionDetailsPanel *panel)
{
gchar *sha1;
- gitg_runner_cancel (panel->priv->runner);
+ gitg_io_cancel (GITG_IO (panel->priv->shell));
gtk_text_buffer_set_text (gtk_text_view_get_buffer (panel->priv->text_view),
"",
@@ -657,14 +657,14 @@ update_details (GitgRevisionDetailsPanel *panel)
sha1 = gitg_revision_get_sha1 (panel->priv->revision);
- gitg_repository_run_commandv (panel->priv->repository,
- panel->priv->runner,
- NULL,
- "show",
- "--numstat",
- "--pretty=format:%s%n%n%b%n\x01",
- sha1,
- NULL);
+ gitg_shell_run (panel->priv->shell,
+ gitg_command_newv (panel->priv->repository,
+ "show",
+ "--numstat",
+ "--pretty=format:%s%n%n%b%n\x01",
+ sha1,
+ NULL),
+ NULL);
g_free (sha1);
}
diff --git a/gitg/gitg-revision-files-panel.c b/gitg/gitg-revision-files-panel.c
index 985cd1c..94f1534 100644
--- a/gitg/gitg-revision-files-panel.c
+++ b/gitg/gitg-revision-files-panel.c
@@ -27,7 +27,7 @@
#include <gio/gio.h>
#include <stdlib.h>
#include <libgitg/gitg-revision.h>
-#include <libgitg/gitg-runner.h>
+#include <libgitg/gitg-shell.h>
#include "gitg-revision-files-panel.h"
#include "gitg-utils.h"
@@ -54,7 +54,7 @@ struct _GitgRevisionFilesViewPrivate
{
GtkTreeView *tree_view;
GtkSourceView *contents;
- GitgRunner *content_runner;
+ GitgShell *content_shell;
GtkTreeStore *store;
gchar *drag_dir;
@@ -62,7 +62,7 @@ struct _GitgRevisionFilesViewPrivate
GitgRepository *repository;
GitgRevision *revision;
- GitgRunner *loader;
+ GitgShell *loader;
GtkTreePath *load_path;
gboolean skipped_blank_line;
@@ -127,7 +127,7 @@ gitg_revision_files_view_finalize (GObject *object)
g_strfreev (self->priv->drag_files);
}
- gitg_runner_cancel (self->priv->loader);
+ gitg_io_cancel (GITG_IO (self->priv->loader));
g_object_unref (self->priv->loader);
G_OBJECT_CLASS (gitg_revision_files_view_parent_class)->finalize (object);
@@ -150,7 +150,7 @@ set_revision (GitgRevisionFilesView *files_view,
return;
}
- gitg_runner_cancel (files_view->priv->loader);
+ gitg_io_cancel (GITG_IO (files_view->priv->loader));
gtk_tree_store_clear (files_view->priv->store);
if (files_view->priv->repository)
@@ -270,7 +270,7 @@ on_selection_changed (GtkTreeSelection *selection,
GtkTreeModel *model;
GtkTreeIter iter;
- gitg_runner_cancel (tree->priv->content_runner);
+ gitg_io_cancel (GITG_IO (tree->priv->content_shell));
gtk_text_buffer_set_text (buffer, "", -1);
@@ -326,13 +326,13 @@ on_selection_changed (GtkTreeSelection *selection,
gchar *id = node_identity (tree, &iter);
- gitg_repository_run_commandv (tree->priv->repository,
- tree->priv->content_runner,
- NULL,
- "show",
- "--encoding=UTF-8",
- id,
- NULL);
+ gitg_shell_run (tree->priv->content_shell,
+ gitg_command_newv (tree->priv->repository,
+ "show",
+ "--encoding=UTF-8",
+ id,
+ NULL),
+ NULL);
g_free (id);
}
@@ -857,8 +857,8 @@ append_node (GitgRevisionFilesView *tree,
}
static void
-on_update (GitgRunner *runner,
- gchar **buffer,
+on_update (GitgShell *shell,
+ gchar **buffer,
GitgRevisionFilesView *tree)
{
gchar *line;
@@ -919,9 +919,9 @@ compare_func (GtkTreeModel *model,
}
static void
-on_contents_update (GitgRunner *runner,
- gchar **buffer,
- GitgRevisionFilesView *tree)
+on_contents_update (GitgShell *shell,
+ gchar **buffer,
+ GitgRevisionFilesView *tree)
{
gchar *line;
GtkTextBuffer *buf;
@@ -943,7 +943,7 @@ on_contents_update (GitgRunner *runner,
if (content_type && !gitg_utils_can_display_content_type (content_type))
{
- gitg_runner_cancel (runner);
+ gitg_io_cancel (GITG_IO (shell));
show_binary_information (tree);
}
else
@@ -978,14 +978,14 @@ gitg_revision_files_view_init (GitgRevisionFilesView *self)
NAME_COLUMN,
GTK_SORT_ASCENDING);
- self->priv->loader = gitg_runner_new (1000);
+ self->priv->loader = gitg_shell_new (1000);
g_signal_connect (self->priv->loader,
"update",
G_CALLBACK (on_update),
self);
- self->priv->content_runner = gitg_runner_new (5000);
- g_signal_connect (self->priv->content_runner,
+ self->priv->content_shell = gitg_shell_new (5000);
+ g_signal_connect (self->priv->content_shell,
"update",
G_CALLBACK (on_contents_update),
self);
@@ -1017,7 +1017,7 @@ static void
load_node (GitgRevisionFilesView *tree,
GtkTreeIter *parent)
{
- if (gitg_runner_running (tree->priv->loader))
+ if (gitg_io_get_running (GITG_IO (tree->priv->loader)))
{
return;
}
@@ -1041,12 +1041,12 @@ load_node (GitgRevisionFilesView *tree,
}
tree->priv->skipped_blank_line = FALSE;
- gitg_repository_run_commandv (tree->priv->repository,
- tree->priv->loader,
- NULL,
- "show",
- "--encoding=UTF-8",
- id,
- NULL);
+ gitg_shell_run (tree->priv->loader,
+ gitg_command_newv (tree->priv->repository,
+ "show",
+ "--encoding=UTF-8",
+ id,
+ NULL),
+ NULL);
g_free (id);
}
diff --git a/gitg/gitg-window.c b/gitg/gitg-window.c
index 5136d65..7e0f012 100644
--- a/gitg/gitg-window.c
+++ b/gitg/gitg-window.c
@@ -26,7 +26,6 @@
#include <glib/gi18n.h>
#include <libgitg/gitg-config.h>
#include <libgitg/gitg-ref.h>
-#include <libgitg/gitg-runner.h>
#include <libgitg/gitg-hash.h>
#include "config.h"
@@ -158,31 +157,31 @@ static GtkBuildableIface parent_iface;
static GtkWindowClass *parent_class = NULL;
static void
-on_branch_action_runner_end (GitgRunner *runner,
- gboolean cancelled,
- GitgWindow *window)
+on_branch_action_shell_end (GitgShell *shell,
+ gboolean cancelled,
+ GitgWindow *window)
{
- window->priv->branch_actions = g_list_remove (window->priv->branch_actions, runner);
- g_object_unref (runner);
+ window->priv->branch_actions = g_list_remove (window->priv->branch_actions, shell);
+ g_object_unref (shell);
}
gboolean
gitg_window_add_branch_action (GitgWindow *window,
- GitgRunner *runner)
+ GitgShell *shell)
{
- if (runner != NULL && gitg_runner_running (runner))
+ if (shell != NULL && gitg_io_get_running (GITG_IO (shell)))
{
- window->priv->branch_actions = g_list_prepend (window->priv->branch_actions, runner);
+ window->priv->branch_actions = g_list_prepend (window->priv->branch_actions, shell);
- g_signal_connect (runner, "end-loading", G_CALLBACK (on_branch_action_runner_end), window);
+ g_signal_connect (shell, "end", G_CALLBACK (on_branch_action_shell_end), window);
}
- else if (runner)
+ else if (shell)
{
- g_object_unref (runner);
- runner = NULL;
+ g_object_unref (shell);
+ shell = NULL;
}
- return runner != NULL;
+ return shell != NULL;
}
static void
@@ -198,7 +197,7 @@ gitg_window_finalize (GObject *object)
for (item = copy; item; item = g_list_next (item))
{
- gitg_runner_cancel (GITG_RUNNER (item->data));
+ gitg_io_cancel (item->data);
}
g_list_free (copy);
@@ -1217,7 +1216,7 @@ on_repository_loaded (GitgRepository *repository,
}
static void
-on_update (GitgRunner *loader,
+on_update (GitgShell *loader,
gchar **revisions,
GitgWindow *window)
{
@@ -1782,7 +1781,7 @@ load_repository (GitgWindow *window,
gtk_tree_view_set_model (window->priv->tree_view,
GTK_TREE_MODEL (window->priv->repository));
- GitgRunner *loader = gitg_repository_get_loader (window->priv->repository);
+ GitgShell *loader = gitg_repository_get_loader (window->priv->repository);
gitg_window_set_select_on_load (window, selection);
diff --git a/gitg/gitg-window.h b/gitg/gitg-window.h
index 648f38e..3245013 100644
--- a/gitg/gitg-window.h
+++ b/gitg/gitg-window.h
@@ -25,14 +25,15 @@
#include <gtk/gtk.h>
#include <libgitg/gitg-repository.h>
+#include <libgitg/gitg-shell.h>
G_BEGIN_DECLS
-#define GITG_TYPE_WINDOW (gitg_window_get_type ())
-#define GITG_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GITG_TYPE_WINDOW, GitgWindow))
+#define GITG_TYPE_WINDOW (gitg_window_get_type ())
+#define GITG_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GITG_TYPE_WINDOW, GitgWindow))
#define GITG_WINDOW_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GITG_TYPE_WINDOW, GitgWindow const))
#define GITG_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GITG_TYPE_WINDOW, GitgWindowClass))
-#define GITG_IS_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GITG_TYPE_WINDOW))
+#define GITG_IS_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GITG_TYPE_WINDOW))
#define GITG_IS_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GITG_TYPE_WINDOW))
#define GITG_WINDOW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GITG_TYPE_WINDOW, GitgWindowClass))
@@ -40,13 +41,15 @@ typedef struct _GitgWindow GitgWindow;
typedef struct _GitgWindowClass GitgWindowClass;
typedef struct _GitgWindowPrivate GitgWindowPrivate;
-struct _GitgWindow {
+struct _GitgWindow
+{
GtkWindow parent;
GitgWindowPrivate *priv;
};
-struct _GitgWindowClass {
+struct _GitgWindowClass
+{
GtkWindowClass parent_class;
};
@@ -71,10 +74,10 @@ gboolean gitg_window_load_repository_from_environment (GitgWindow *window,
void gitg_window_show_commit (GitgWindow *window);
-GitgRepository *gitg_window_get_repository(GitgWindow *window);
+GitgRepository *gitg_window_get_repository (GitgWindow *window);
void gitg_window_set_select_on_load (GitgWindow *window, gchar const *selection);
-gboolean gitg_window_add_branch_action (GitgWindow *window, GitgRunner *runner);
+gboolean gitg_window_add_branch_action (GitgWindow *window, GitgShell *shell);
gboolean gitg_window_select (GitgWindow *window, gchar const *selection);
gboolean gitg_window_activate (GitgWindow *window, gchar const *activatable, gchar const *action);
diff --git a/libgitg/Makefile.am b/libgitg/Makefile.am
index cc0c2e8..a6f6572 100644
--- a/libgitg/Makefile.am
+++ b/libgitg/Makefile.am
@@ -30,7 +30,11 @@ INST_H_FILES = \
gitg-ref.h \
gitg-repository.h \
gitg-revision.h \
- gitg-runner.h
+ gitg-runner.h \
+ gitg-command.h \
+ gitg-shell.h \
+ gitg-io.h \
+ gitg-line-parser.h
NOINST_H_FILES = \
gitg-convert.h \
@@ -57,7 +61,11 @@ C_FILES = \
gitg-revision.c \
gitg-runner.c \
gitg-smart-charset-converter.c \
- gitg-encodings.c
+ gitg-encodings.c \
+ gitg-command.c \
+ gitg-io.c \
+ gitg-shell.c \
+ gitg-line-parser.c
ENUM_H_FILES = \
gitg-changed-file.h
diff --git a/libgitg/gitg-command.c b/libgitg/gitg-command.c
new file mode 100644
index 0000000..7395b25
--- /dev/null
+++ b/libgitg/gitg-command.c
@@ -0,0 +1,491 @@
+#include "gitg-command.h"
+
+#define GITG_COMMAND_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE((object), GITG_TYPE_COMMAND, GitgCommandPrivate))
+
+#define CONST_CONST(x) ((gchar const * const *)x)
+
+struct _GitgCommandPrivate
+{
+ GitgRepository *repository;
+ gchar **arguments;
+ gchar **environment;
+ GFile *working_directory;
+};
+
+G_DEFINE_TYPE (GitgCommand, gitg_command, G_TYPE_INITIALLY_UNOWNED)
+
+enum
+{
+ PROP_0,
+ PROP_REPOSITORY,
+ PROP_ARGUMENTS,
+ PROP_ENVIRONMENT,
+ PROP_WORKING_DIRECTORY
+};
+
+static void
+gitg_command_finalize (GObject *object)
+{
+ GitgCommand *command;
+
+ command = GITG_COMMAND (object);
+
+ g_strfreev (command->priv->arguments);
+ g_strfreev (command->priv->environment);
+
+ G_OBJECT_CLASS (gitg_command_parent_class)->finalize (object);
+}
+
+static void
+gitg_command_dispose (GObject *object)
+{
+ GitgCommand *command;
+
+ command = GITG_COMMAND (object);
+
+ if (command->priv->repository != NULL)
+ {
+ g_object_unref (command->priv->repository);
+ command->priv->repository = NULL;
+ }
+
+ G_OBJECT_CLASS (gitg_command_parent_class)->dispose (object);
+}
+
+static void
+gitg_command_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GitgCommand *self = GITG_COMMAND (object);
+
+ switch (prop_id)
+ {
+ case PROP_REPOSITORY:
+ self->priv->repository = g_value_dup_object (value);
+ break;
+ case PROP_ARGUMENTS:
+ gitg_command_set_arguments (self,
+ g_value_get_boxed (value));
+ break;
+ case PROP_ENVIRONMENT:
+ gitg_command_set_environment (self,
+ g_value_get_boxed (value));
+ break;
+ case PROP_WORKING_DIRECTORY:
+ gitg_command_set_working_directory (self,
+ g_value_get_object (value));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gitg_command_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GitgCommand *self = GITG_COMMAND (object);
+
+ switch (prop_id)
+ {
+ case PROP_REPOSITORY:
+ g_value_set_object (value, self->priv->repository);
+ break;
+ case PROP_ARGUMENTS:
+ g_value_set_boxed (value, self->priv->arguments);
+ break;
+ case PROP_ENVIRONMENT:
+ g_value_set_boxed (value, self->priv->environment);
+ break;
+ case PROP_WORKING_DIRECTORY:
+ g_value_take_object (value, gitg_command_get_working_directory (self));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gitg_command_class_init (GitgCommandClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = gitg_command_finalize;
+ object_class->dispose = gitg_command_dispose;
+
+ object_class->get_property = gitg_command_get_property;
+ object_class->set_property = gitg_command_set_property;
+
+ g_type_class_add_private (object_class, sizeof(GitgCommandPrivate));
+
+ g_object_class_install_property (object_class,
+ PROP_REPOSITORY,
+ g_param_spec_object ("repository",
+ "Repository",
+ "Repository",
+ GITG_TYPE_REPOSITORY,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+
+ g_object_class_install_property (object_class,
+ PROP_ARGUMENTS,
+ g_param_spec_boxed ("arguments",
+ "Arguments",
+ "Arguments",
+ G_TYPE_STRV,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+
+ g_object_class_install_property (object_class,
+ PROP_ENVIRONMENT,
+ g_param_spec_boxed ("environment",
+ "Environment",
+ "Environment",
+ G_TYPE_STRV,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property (object_class,
+ PROP_WORKING_DIRECTORY,
+ g_param_spec_object ("working-directory",
+ "Working Directory",
+ "Working directory",
+ G_TYPE_FILE,
+ G_PARAM_READWRITE));
+}
+
+static void
+gitg_command_init (GitgCommand *self)
+{
+ self->priv = GITG_COMMAND_GET_PRIVATE (self);
+}
+
+static gchar **
+collect_arguments (va_list ap)
+{
+ GPtrArray *arguments;
+ gchar const *arg;
+
+ arguments = g_ptr_array_new ();
+
+ while ((arg = va_arg (ap, gchar const *)) != NULL)
+ {
+ g_ptr_array_add (arguments, g_strdup (arg));
+ }
+
+ g_ptr_array_add (arguments, NULL);
+
+ return (gchar **)g_ptr_array_free (arguments, FALSE);
+}
+
+static gchar **
+combine_environment (gchar const * const *environment)
+{
+ GPtrArray *ret;
+
+ ret = g_ptr_array_new ();
+
+ while (*environment)
+ {
+ gchar const *key = *environment++;
+ gchar const *value = *environment++;
+
+ gchar *combined = g_strconcat (key, "=", value, NULL);
+
+ g_ptr_array_add (ret, combined);
+ }
+
+ g_ptr_array_add (ret, NULL);
+
+ return (gchar **)g_ptr_array_free (ret, FALSE);
+}
+
+GitgCommand *
+gitg_command_new (GitgRepository *repository,
+ gchar const * const *arguments)
+{
+ g_return_val_if_fail (repository == NULL || GITG_IS_REPOSITORY (repository), NULL);
+
+ return g_object_new (GITG_TYPE_COMMAND,
+ "repository", repository,
+ "arguments", arguments,
+ NULL);
+}
+
+GitgCommand *
+gitg_command_newv (GitgRepository *repository,
+ ...)
+{
+ va_list ap;
+ GitgCommand *ret;
+ gchar **arguments;
+
+ g_return_val_if_fail (repository == NULL || GITG_IS_REPOSITORY (repository), NULL);
+
+ va_start (ap, repository);
+
+ arguments = collect_arguments (ap);
+ ret = gitg_command_new (repository, CONST_CONST (arguments));
+
+ g_strfreev (arguments);
+ va_end (ap);
+
+ return ret;
+}
+
+GitgRepository *
+gitg_command_get_repository (GitgCommand *command)
+{
+ g_return_val_if_fail (GITG_IS_COMMAND (command), NULL);
+
+ return command->priv->repository;
+}
+
+void
+gitg_command_set_arguments (GitgCommand *command,
+ gchar const * const *arguments)
+{
+ GPtrArray *ret;
+
+ g_return_if_fail (GITG_IS_COMMAND (command));
+
+ ret = g_ptr_array_new ();
+
+ if (command->priv->repository)
+ {
+ GFile *git_dir;
+ GFile *work_tree;
+
+ gchar *git_dir_path;
+ gchar *work_tree_path;
+
+ git_dir = gitg_repository_get_git_dir (command->priv->repository);
+ work_tree = gitg_repository_get_work_tree (command->priv->repository);
+
+ git_dir_path = g_file_get_path (git_dir);
+ work_tree_path = g_file_get_path (work_tree);
+
+ g_object_unref (git_dir);
+ g_object_unref (work_tree);
+
+ g_ptr_array_add (ret, g_strdup ("git"));
+ g_ptr_array_add (ret, g_strdup ("--git-dir"));
+ g_ptr_array_add (ret, git_dir_path);
+ g_ptr_array_add (ret, g_strdup ("--work-tree"));
+ g_ptr_array_add (ret, work_tree_path);
+ }
+
+ while (*arguments)
+ {
+ g_ptr_array_add (ret, g_strdup (*arguments++));
+ }
+
+ g_ptr_array_add (ret, NULL);
+
+ g_strfreev (command->priv->arguments);
+ command->priv->arguments = (gchar **)g_ptr_array_free (ret, FALSE);
+
+ g_object_notify (G_OBJECT (command), "arguments");
+}
+
+void
+gitg_command_set_argumentsv (GitgCommand *command,
+ ...)
+{
+ va_list ap;
+ gchar **arguments;
+
+ g_return_if_fail (GITG_IS_COMMAND (command));
+
+ va_start (ap, command);
+ arguments = collect_arguments (ap);
+ va_end (ap);
+
+ gitg_command_set_arguments (command, CONST_CONST (arguments));
+
+ g_strfreev (arguments);
+}
+
+void
+gitg_command_add_arguments (GitgCommand *command,
+ gchar const * const *arguments)
+{
+ GPtrArray *args;
+ gchar **ptr;
+
+ g_return_if_fail (GITG_IS_COMMAND (command));
+
+ args = g_ptr_array_new ();
+
+ for (ptr = command->priv->arguments; *ptr; ++ptr)
+ {
+ g_ptr_array_add (args, *ptr);
+ }
+
+ while (*arguments)
+ {
+ g_ptr_array_add (args, g_strdup (*arguments++));
+ }
+
+ g_free (command->priv->arguments);
+
+ g_ptr_array_add (args, NULL);
+ command->priv->arguments = (gchar **)g_ptr_array_free (args, FALSE);
+
+ g_object_notify (G_OBJECT (command), "arguments");
+}
+
+void
+gitg_command_add_argumentsv (GitgCommand *command,
+ ...)
+{
+ va_list ap;
+ gchar **arguments;
+
+ g_return_if_fail (GITG_IS_COMMAND (command));
+
+ va_start (ap, command);
+ arguments = collect_arguments (ap);
+ va_end (ap);
+
+ gitg_command_add_arguments (command, CONST_CONST (arguments));
+
+ g_strfreev (arguments);
+}
+
+gchar const * const *
+gitg_command_get_arguments (GitgCommand *command)
+{
+ g_return_val_if_fail (GITG_IS_COMMAND (command), NULL);
+ return CONST_CONST (command->priv->arguments);
+}
+
+void
+gitg_command_set_environment (GitgCommand *command,
+ gchar const * const *environment)
+{
+ g_return_if_fail (GITG_IS_COMMAND (command));
+
+ g_strfreev (command->priv->environment);
+ command->priv->environment = combine_environment (environment);
+
+ g_object_notify (G_OBJECT (command), "environment");
+}
+
+void
+gitg_command_set_environmentv (GitgCommand *command,
+ ...)
+{
+ va_list ap;
+ gchar **environment;
+
+ g_return_if_fail (GITG_IS_COMMAND (command));
+
+ va_start (ap, command);
+ environment = collect_arguments (ap);
+ va_end (ap);
+
+ gitg_command_set_environment (command, CONST_CONST (environment));
+
+ g_strfreev (environment);
+}
+
+void
+gitg_command_add_environment (GitgCommand *command,
+ gchar const * const *environment)
+{
+ GPtrArray *args;
+ gchar **combined;
+ gchar **ptr;
+
+ g_return_if_fail (GITG_IS_COMMAND (command));
+
+ args = g_ptr_array_new ();
+
+ for (ptr = command->priv->environment; *ptr; ++ptr)
+ {
+ g_ptr_array_add (args, *ptr);
+ }
+
+ combined = combine_environment (environment);
+
+ for (ptr = combined; *ptr; ++ptr)
+ {
+ g_ptr_array_add (args, *ptr);
+ }
+
+ g_free (combined);
+ g_free (command->priv->environment);
+
+ g_ptr_array_add (args, NULL);
+
+ command->priv->environment = (gchar **)g_ptr_array_free (args, FALSE);
+
+ g_object_notify (G_OBJECT (command), "arguments");
+}
+
+void
+gitg_command_add_environmentv (GitgCommand *command,
+ ...)
+{
+ va_list ap;
+ gchar **environment;
+
+ g_return_if_fail (GITG_IS_COMMAND (command));
+
+ va_start (ap, command);
+ environment = collect_arguments (ap);
+ va_end (ap);
+
+ gitg_command_add_environment (command, CONST_CONST (environment));
+ g_strfreev (environment);
+}
+
+gchar const * const *
+gitg_command_get_environment (GitgCommand *command)
+{
+ g_return_val_if_fail (GITG_IS_COMMAND (command), NULL);
+
+ return CONST_CONST (command->priv->environment);
+}
+
+void
+gitg_command_set_working_directory (GitgCommand *command,
+ GFile *working_directory)
+{
+ g_return_if_fail (GITG_IS_COMMAND (command));
+ g_return_if_fail (working_directory == NULL || G_IS_FILE (working_directory));
+
+ if (command->priv->working_directory)
+ {
+ g_object_unref (command->priv->working_directory);
+ command->priv->working_directory = NULL;
+ }
+
+ if (working_directory)
+ {
+ command->priv->working_directory = g_file_dup (working_directory);
+ }
+
+ g_object_notify (G_OBJECT (command), "working-directory");
+}
+
+GFile *
+gitg_command_get_working_directory (GitgCommand *command)
+{
+ g_return_val_if_fail (GITG_IS_COMMAND (command), NULL);
+
+ if (command->priv->working_directory)
+ {
+ return g_file_dup (command->priv->working_directory);
+ }
+ else if (command->priv->repository)
+ {
+ return gitg_repository_get_work_tree (command->priv->repository);
+ }
+
+ return NULL;
+}
diff --git a/libgitg/gitg-command.h b/libgitg/gitg-command.h
new file mode 100644
index 0000000..f31c2c6
--- /dev/null
+++ b/libgitg/gitg-command.h
@@ -0,0 +1,76 @@
+#ifndef __GITG_COMMAND_H__
+#define __GITG_COMMAND_H__
+
+#include <glib-object.h>
+#include <libgitg/gitg-repository.h>
+
+G_BEGIN_DECLS
+
+#define GITG_TYPE_COMMAND (gitg_command_get_type ())
+#define GITG_COMMAND(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GITG_TYPE_COMMAND, GitgCommand))
+#define GITG_COMMAND_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GITG_TYPE_COMMAND, GitgCommand const))
+#define GITG_COMMAND_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GITG_TYPE_COMMAND, GitgCommandClass))
+#define GITG_IS_COMMAND(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GITG_TYPE_COMMAND))
+#define GITG_IS_COMMAND_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GITG_TYPE_COMMAND))
+#define GITG_COMMAND_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GITG_TYPE_COMMAND, GitgCommandClass))
+
+typedef struct _GitgCommand GitgCommand;
+typedef struct _GitgCommandClass GitgCommandClass;
+typedef struct _GitgCommandPrivate GitgCommandPrivate;
+
+struct _GitgCommand
+{
+ /*< private >*/
+ GInitiallyUnowned parent;
+
+ GitgCommandPrivate *priv;
+
+ /*< public >*/
+};
+
+struct _GitgCommandClass
+{
+ /*< private >*/
+ GInitiallyUnownedClass parent_class;
+
+ /*< public >*/
+};
+
+GType gitg_command_get_type (void) G_GNUC_CONST;
+
+GitgCommand *gitg_command_new (GitgRepository *repository,
+ gchar const * const *arguments);
+GitgCommand *gitg_command_newv (GitgRepository *repository,
+ ...) G_GNUC_NULL_TERMINATED;
+
+GitgRepository *gitg_command_get_repository (GitgCommand *command);
+
+GFile *gitg_command_get_working_directory (GitgCommand *command);
+void gitg_command_set_working_directory (GitgCommand *command,
+ GFile *file);
+
+void gitg_command_set_arguments (GitgCommand *command,
+ gchar const * const *arguments);
+void gitg_command_set_argumentsv (GitgCommand *command,
+ ...) G_GNUC_NULL_TERMINATED;
+void gitg_command_add_arguments (GitgCommand *command,
+ gchar const * const *arguments);
+void gitg_command_add_argumentsv (GitgCommand *command,
+ ...) G_GNUC_NULL_TERMINATED;
+
+gchar const * const *gitg_command_get_arguments (GitgCommand *command);
+
+void gitg_command_set_environment (GitgCommand *command,
+ gchar const * const *environment);
+void gitg_command_set_environmentv (GitgCommand *command,
+ ...) G_GNUC_NULL_TERMINATED;
+void gitg_command_add_environment (GitgCommand *command,
+ gchar const * const *environment);
+void gitg_command_add_environmentv (GitgCommand *command,
+ ...) G_GNUC_NULL_TERMINATED;
+
+gchar const * const *gitg_command_get_environment (GitgCommand *command);
+
+G_END_DECLS
+
+#endif /* __GITG_COMMAND_H__ */
diff --git a/libgitg/gitg-commit.c b/libgitg/gitg-commit.c
index 7ad4048..12f5183 100644
--- a/libgitg/gitg-commit.c
+++ b/libgitg/gitg-commit.c
@@ -21,13 +21,13 @@
*/
#include "gitg-commit.h"
-#include "gitg-runner.h"
+#include "gitg-shell.h"
#include "gitg-changed-file.h"
#include "gitg-config.h"
#include <string.h>
-#define GITG_COMMIT_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE((object), GITG_TYPE_COMMIT, GitgCommitPrivate))
+#define GITG_COMMIT_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), GITG_TYPE_COMMIT, GitgCommitPrivate))
#define CAN_DELETE_KEY "CanDeleteKey"
@@ -49,7 +49,7 @@ enum
struct _GitgCommitPrivate
{
GitgRepository *repository;
- GitgRunner *runner;
+ GitgShell *shell;
guint update_id;
guint end_id;
@@ -59,108 +59,124 @@ struct _GitgCommitPrivate
static guint commit_signals[LAST_SIGNAL] = { 0 };
-G_DEFINE_TYPE(GitgCommit, gitg_commit, G_TYPE_OBJECT)
+G_DEFINE_TYPE (GitgCommit, gitg_commit, G_TYPE_OBJECT)
-static void on_changed_file_changed(GitgChangedFile *file, GitgCommit *commit);
+static void on_changed_file_changed (GitgChangedFile *file, GitgCommit *commit);
GQuark
-gitg_commit_error_quark()
+gitg_commit_error_quark ()
{
static GQuark quark = 0;
- if (G_UNLIKELY(quark == 0))
+ if (G_UNLIKELY (quark == 0))
quark = g_quark_from_string ("gitg_commit_error");
return quark;
}
static void
-runner_cancel(GitgCommit *commit)
+shell_cancel (GitgCommit *commit)
{
if (commit->priv->update_id)
{
- g_signal_handler_disconnect(commit->priv->runner, commit->priv->update_id);
+ g_signal_handler_disconnect (commit->priv->shell,
+ commit->priv->update_id);
commit->priv->update_id = 0;
}
if (commit->priv->end_id)
{
- g_signal_handler_disconnect(commit->priv->runner, commit->priv->end_id);
+ g_signal_handler_disconnect (commit->priv->shell,
+ commit->priv->end_id);
commit->priv->end_id = 0;
}
- gitg_runner_cancel(commit->priv->runner);
+ gitg_io_cancel (GITG_IO (commit->priv->shell));
}
static void
-gitg_commit_finalize(GObject *object)
+gitg_commit_finalize (GObject *object)
{
- GitgCommit *commit = GITG_COMMIT(object);
+ GitgCommit *commit = GITG_COMMIT (object);
- runner_cancel(commit);
- g_object_unref(commit->priv->runner);
+ shell_cancel (commit);
+ g_object_unref (commit->priv->shell);
- g_hash_table_destroy(commit->priv->files);
+ g_hash_table_destroy (commit->priv->files);
- G_OBJECT_CLASS(gitg_commit_parent_class)->finalize(object);
+ G_OBJECT_CLASS (gitg_commit_parent_class)->finalize (object);
}
static void
-gitg_commit_dispose(GObject *object)
+gitg_commit_dispose (GObject *object)
{
- GitgCommit *self = GITG_COMMIT(object);
+ GitgCommit *self = GITG_COMMIT (object);
if (self->priv->repository)
{
- g_signal_handlers_disconnect_by_func(self->priv->repository, G_CALLBACK(gitg_commit_refresh), self);
+ g_signal_handlers_disconnect_by_func (self->priv->repository,
+ G_CALLBACK (gitg_commit_refresh),
+ self);
- g_object_unref(self->priv->repository);
+ g_object_unref (self->priv->repository);
self->priv->repository = NULL;
}
}
static void
-gitg_commit_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
+gitg_commit_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
{
- GitgCommit *self = GITG_COMMIT(object);
+ GitgCommit *self = GITG_COMMIT (object);
switch (prop_id)
{
case PROP_REPOSITORY:
- g_value_set_object(value, self->priv->repository);
- break;
+ g_value_set_object (value, self->priv->repository);
+ break;
default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
- break;
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
}
}
static void
-gitg_commit_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
+gitg_commit_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
{
- GitgCommit *self = GITG_COMMIT(object);
+ GitgCommit *self = GITG_COMMIT (object);
switch (prop_id)
{
case PROP_REPOSITORY:
{
if (self->priv->repository)
- g_object_unref(self->priv->repository);
+ {
+ g_object_unref (self->priv->repository);
+ }
- self->priv->repository = g_value_dup_object(value);
- g_signal_connect_swapped(self->priv->repository, "load", G_CALLBACK(gitg_commit_refresh), self);
+ self->priv->repository = g_value_dup_object (value);
+
+ g_signal_connect_swapped (self->priv->repository,
+ "load",
+ G_CALLBACK (gitg_commit_refresh),
+ self);
}
break;
default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
-gitg_commit_class_init(GitgCommitClass *klass)
+gitg_commit_class_init (GitgCommitClass *klass)
{
- GObjectClass *object_class = G_OBJECT_CLASS(klass);
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->dispose = gitg_commit_dispose;
object_class->finalize = gitg_commit_finalize;
@@ -168,104 +184,136 @@ gitg_commit_class_init(GitgCommitClass *klass)
object_class->set_property = gitg_commit_set_property;
object_class->get_property = gitg_commit_get_property;
- g_object_class_install_property(object_class, PROP_REPOSITORY,
- g_param_spec_object("repository",
- "REPOSITORY",
- "Repository",
- GITG_TYPE_REPOSITORY,
- G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+ g_object_class_install_property (object_class,
+ PROP_REPOSITORY,
+ g_param_spec_object ("repository",
+ "REPOSITORY",
+ "Repository",
+ GITG_TYPE_REPOSITORY,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
commit_signals[INSERTED] =
- g_signal_new ("inserted",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (GitgCommitClass, inserted),
- NULL, NULL,
- g_cclosure_marshal_VOID__OBJECT,
- G_TYPE_NONE,
- 1,
- GITG_TYPE_CHANGED_FILE);
+ g_signal_new ("inserted",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GitgCommitClass,
+ inserted),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__OBJECT,
+ G_TYPE_NONE,
+ 1,
+ GITG_TYPE_CHANGED_FILE);
commit_signals[REMOVED] =
- g_signal_new ("removed",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (GitgCommitClass, removed),
- NULL, NULL,
- g_cclosure_marshal_VOID__OBJECT,
- G_TYPE_NONE,
- 1,
- GITG_TYPE_CHANGED_FILE);
-
- g_type_class_add_private(object_class, sizeof(GitgCommitPrivate));
+ g_signal_new ("removed",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GitgCommitClass,
+ removed),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__OBJECT,
+ G_TYPE_NONE,
+ 1,
+ GITG_TYPE_CHANGED_FILE);
+
+ g_type_class_add_private (object_class, sizeof (GitgCommitPrivate));
}
static void
-gitg_commit_init(GitgCommit *self)
+gitg_commit_init (GitgCommit *self)
{
- self->priv = GITG_COMMIT_GET_PRIVATE(self);
+ self->priv = GITG_COMMIT_GET_PRIVATE (self);
- self->priv->runner = gitg_runner_new(10000);
- self->priv->files = g_hash_table_new_full(g_file_hash, (GEqualFunc)g_file_equal, (GDestroyNotify)g_object_unref, (GDestroyNotify)g_object_unref);
+ self->priv->shell = gitg_shell_new (10000);
+ self->priv->files = g_hash_table_new_full (g_file_hash,
+ (GEqualFunc)g_file_equal,
+ (GDestroyNotify)g_object_unref,
+ (GDestroyNotify)g_object_unref);
}
GitgCommit *
-gitg_commit_new(GitgRepository *repository)
+gitg_commit_new (GitgRepository *repository)
{
- return g_object_new(GITG_TYPE_COMMIT, "repository", repository, NULL);
+ return g_object_new (GITG_TYPE_COMMIT, "repository", repository, NULL);
}
static void
-runner_connect(GitgCommit *commit, GCallback updatefunc, GCallback endfunc)
+shell_connect (GitgCommit *commit,
+ GCallback updatefunc,
+ GCallback endfunc)
{
if (commit->priv->update_id)
{
- g_signal_handler_disconnect(commit->priv->runner, commit->priv->update_id);
+ g_signal_handler_disconnect (commit->priv->shell,
+ commit->priv->update_id);
commit->priv->update_id = 0;
}
if (commit->priv->end_id)
{
- g_signal_handler_disconnect(commit->priv->runner, commit->priv->end_id);
+ g_signal_handler_disconnect (commit->priv->shell,
+ commit->priv->end_id);
commit->priv->end_id = 0;
}
if (updatefunc)
- commit->priv->update_id = g_signal_connect(commit->priv->runner, "update", updatefunc, commit);
+ {
+ commit->priv->update_id = g_signal_connect (commit->priv->shell,
+ "update",
+ updatefunc,
+ commit);
+ }
if (endfunc)
- commit->priv->end_id = g_signal_connect(commit->priv->runner, "end-loading", endfunc, commit);
+ {
+ commit->priv->end_id = g_signal_connect (commit->priv->shell,
+ "end",
+ endfunc,
+ commit);
+ }
}
static void
-update_changed_file_status(GitgChangedFile *file, char const *action, gchar const *mode)
+update_changed_file_status (GitgChangedFile *file,
+ char const *action,
+ gchar const *mode)
{
GitgChangedFileStatus status;
- if (strcmp(action, "D") == 0)
+ if (strcmp (action, "D") == 0)
+ {
status = GITG_CHANGED_FILE_STATUS_DELETED;
- else if (strcmp(mode, "000000") == 0)
+ }
+ else if (strcmp (mode, "000000") == 0)
+ {
status = GITG_CHANGED_FILE_STATUS_NEW;
+ }
else
+ {
status = GITG_CHANGED_FILE_STATUS_MODIFIED;
+ }
- gitg_changed_file_set_status(file, status);
+ gitg_changed_file_set_status (file, status);
}
static void
-add_files(GitgCommit *commit, gchar **buffer, gboolean cached)
+add_files (GitgCommit *commit,
+ gchar **buffer,
+ gboolean cached)
{
gchar *line;
while ((line = *buffer++) != NULL)
{
- gchar **parts = g_strsplit_set(line, " \t", 0);
- guint len = g_strv_length(parts);
+ gchar **parts = g_strsplit_set (line, " \t", 0);
+ guint len = g_strv_length (parts);
if (len < 6)
{
- g_warning("Invalid line: %s (%d)", line, len);
- g_strfreev(parts);
+ g_warning ("Invalid line: %s (%d)", line, len);
+ g_strfreev (parts);
continue;
}
@@ -282,15 +330,15 @@ add_files(GitgCommit *commit, gchar **buffer, gboolean cached)
if (f)
{
- GitgChangedFileChanges changes = gitg_changed_file_get_changes(f);
+ GitgChangedFileChanges changes = gitg_changed_file_get_changes (f);
- g_object_set_data(G_OBJECT(f), CAN_DELETE_KEY, NULL);
- update_changed_file_status(f, parts[4], mode);
+ g_object_set_data (G_OBJECT (f), CAN_DELETE_KEY, NULL);
+ update_changed_file_status (f, parts[4], mode);
if (cached)
{
- gitg_changed_file_set_sha(f, sha);
- gitg_changed_file_set_mode(f, mode);
+ gitg_changed_file_set_sha (f, sha);
+ gitg_changed_file_set_mode (f, mode);
changes |= GITG_CHANGED_FILE_CHANGES_CACHED;
}
@@ -299,95 +347,134 @@ add_files(GitgCommit *commit, gchar **buffer, gboolean cached)
changes |= GITG_CHANGED_FILE_CHANGES_UNSTAGED;
}
- gitg_changed_file_set_changes(f, changes);
+ gitg_changed_file_set_changes (f, changes);
if ((changes & GITG_CHANGED_FILE_CHANGES_CACHED) && (changes & GITG_CHANGED_FILE_CHANGES_UNSTAGED))
- gitg_changed_file_set_status(f, GITG_CHANGED_FILE_STATUS_MODIFIED);
+ {
+ gitg_changed_file_set_status (f, GITG_CHANGED_FILE_STATUS_MODIFIED);
+ }
- g_object_unref(file);
- g_strfreev(parts);
+ g_object_unref (file);
+ g_strfreev (parts);
continue;
}
- f = gitg_changed_file_new(file);
- update_changed_file_status(f, parts[4], mode);
+ f = gitg_changed_file_new (file);
+ update_changed_file_status (f, parts[4], mode);
- gitg_changed_file_set_sha(f, sha);
- gitg_changed_file_set_mode(f, mode);
+ gitg_changed_file_set_sha (f, sha);
+ gitg_changed_file_set_mode (f, mode);
GitgChangedFileChanges changes;
changes = cached ? GITG_CHANGED_FILE_CHANGES_CACHED : GITG_CHANGED_FILE_CHANGES_UNSTAGED;
- gitg_changed_file_set_changes(f, changes);
+ gitg_changed_file_set_changes (f, changes);
- g_hash_table_insert(commit->priv->files, file, f);
+ g_hash_table_insert (commit->priv->files, file, f);
- g_signal_connect(f, "changed", G_CALLBACK(on_changed_file_changed), commit);
- g_signal_emit(commit, commit_signals[INSERTED], 0, f);
+ g_signal_connect (f, "changed", G_CALLBACK (on_changed_file_changed), commit);
+ g_signal_emit (commit, commit_signals[INSERTED], 0, f);
- g_strfreev(parts);
+ g_strfreev (parts);
}
}
static void
-read_cached_files_update(GitgRunner *runner, gchar **buffer, GitgCommit *commit)
+read_cached_files_update (GitgShell *shell,
+ gchar **buffer,
+ GitgCommit *commit)
{
- add_files(commit, buffer, TRUE);
+ add_files (commit, buffer, TRUE);
}
static gboolean
-delete_file(GFile *key, GitgChangedFile *value, GitgCommit *commit)
+delete_file (GFile *key,
+ GitgChangedFile *value,
+ GitgCommit *commit)
{
- if (!g_object_get_data(G_OBJECT(value), CAN_DELETE_KEY))
+ if (!g_object_get_data (G_OBJECT (value), CAN_DELETE_KEY))
+ {
return FALSE;
+ }
- g_signal_emit(commit, commit_signals[REMOVED], 0, value);
+ g_signal_emit (commit, commit_signals[REMOVED], 0, value);
return TRUE;
}
static void
-refresh_done(GitgRunner *runner, gboolean cancelled, GitgCommit *commit)
+refresh_done (GitgShell *shell,
+ gboolean cancelled,
+ GitgCommit *commit)
{
- g_hash_table_foreach_remove(commit->priv->files, (GHRFunc)delete_file, commit);
+ g_hash_table_foreach_remove (commit->priv->files,
+ (GHRFunc)delete_file,
+ commit);
}
static void
-read_unstaged_files_end(GitgRunner *runner, gboolean cancelled, GitgCommit *commit)
+read_unstaged_files_end (GitgShell *shell,
+ gboolean cancelled,
+ GitgCommit *commit)
{
- gchar *head = gitg_repository_parse_head(commit->priv->repository);
- gitg_runner_cancel(runner);
-
- runner_connect(commit, G_CALLBACK(read_cached_files_update), G_CALLBACK(refresh_done));
- gitg_repository_run_commandv(commit->priv->repository, commit->priv->runner, NULL, "diff-index", "--cached", head, NULL);
- g_free(head);
+ gchar *head = gitg_repository_parse_head (commit->priv->repository);
+ gitg_io_cancel (GITG_IO (shell));
+
+ shell_connect (commit,
+ G_CALLBACK (read_cached_files_update),
+ G_CALLBACK (refresh_done));
+
+ gitg_shell_run (commit->priv->shell,
+ gitg_command_newv (commit->priv->repository,
+ "diff-index",
+ "--no-ext-diff",
+ "--cached",
+ head,
+ NULL),
+ NULL);
+
+ g_free (head);
}
static void
-read_unstaged_files_update(GitgRunner *runner, gchar **buffer, GitgCommit *commit)
+read_unstaged_files_update (GitgShell *shell,
+ gchar **buffer,
+ GitgCommit *commit)
{
- add_files(commit, buffer, FALSE);
+ add_files (commit, buffer, FALSE);
}
static void
-read_other_files_end(GitgRunner *runner, gboolean cancelled, GitgCommit *commit)
+read_other_files_end (GitgShell *shell,
+ gboolean cancelled,
+ GitgCommit *commit)
{
- gitg_runner_cancel(runner);
-
- runner_connect(commit, G_CALLBACK(read_unstaged_files_update), G_CALLBACK(read_unstaged_files_end));
- gitg_repository_run_commandv(commit->priv->repository,commit->priv->runner, NULL, "diff-files", NULL);
+ gitg_io_cancel (GITG_IO (shell));
+
+ shell_connect (commit,
+ G_CALLBACK (read_unstaged_files_update),
+ G_CALLBACK (read_unstaged_files_end));
+
+ gitg_shell_run (commit->priv->shell,
+ gitg_command_newv (commit->priv->repository,
+ "diff-files",
+ "--no-ext-diff",
+ NULL),
+ NULL);
}
static void
-changed_file_new(GitgChangedFile *f)
+changed_file_new (GitgChangedFile *f)
{
- gitg_changed_file_set_status(f, GITG_CHANGED_FILE_STATUS_NEW);
- gitg_changed_file_set_changes(f, GITG_CHANGED_FILE_CHANGES_UNSTAGED);
+ gitg_changed_file_set_status (f, GITG_CHANGED_FILE_STATUS_NEW);
+ gitg_changed_file_set_changes (f, GITG_CHANGED_FILE_CHANGES_UNSTAGED);
- g_object_set_data(G_OBJECT(f), CAN_DELETE_KEY, NULL);
+ g_object_set_data (G_OBJECT (f), CAN_DELETE_KEY, NULL);
}
static void
-read_other_files_update(GitgRunner *runner, gchar **buffer, GitgCommit *commit)
+read_other_files_update (GitgShell *shell,
+ gchar **buffer,
+ GitgCommit *commit)
{
gchar *line;
@@ -395,7 +482,9 @@ read_other_files_update(GitgRunner *runner, gchar **buffer, GitgCommit *commit)
{
/* Skip empty lines */
if (!*line)
+ {
continue;
+ }
/* Check if file is already in our index */
GFile *work_tree = gitg_repository_get_work_tree (commit->priv->repository);
@@ -403,354 +492,484 @@ read_other_files_update(GitgRunner *runner, gchar **buffer, GitgCommit *commit)
g_object_unref (work_tree);
- GitgChangedFile *f = g_hash_table_lookup(commit->priv->files, file);
+ GitgChangedFile *f = g_hash_table_lookup (commit->priv->files, file);
if (f)
{
- changed_file_new(f);
- g_object_unref(file);
+ changed_file_new (f);
+ g_object_unref (file);
continue;
}
- f = gitg_changed_file_new(file);
+ f = gitg_changed_file_new (file);
- changed_file_new(f);
- g_hash_table_insert(commit->priv->files, file, f);
+ changed_file_new (f);
+ g_hash_table_insert (commit->priv->files, file, f);
- g_signal_emit(commit, commit_signals[INSERTED], 0, f);
+ g_signal_emit (commit, commit_signals[INSERTED], 0, f);
}
}
static void
-update_index_end(GitgRunner *runner, gboolean cancelled, GitgCommit *commit)
+update_index_end (GitgShell *shell,
+ gboolean cancelled,
+ GitgCommit *commit)
{
- gitg_runner_cancel(runner);
- runner_connect(commit, G_CALLBACK(read_other_files_update), G_CALLBACK(read_other_files_end));
-
- gitg_repository_run_commandv(commit->priv->repository, commit->priv->runner, NULL, "ls-files", "--others", "--exclude-standard", NULL);
+ gitg_io_cancel (GITG_IO (shell));
+
+ shell_connect (commit,
+ G_CALLBACK (read_other_files_update),
+ G_CALLBACK (read_other_files_end));
+
+ gitg_shell_run (commit->priv->shell,
+ gitg_command_newv (commit->priv->repository,
+ "ls-files",
+ "--others",
+ "--exclude-standard",
+ NULL),
+ NULL);
}
static void
-update_index(GitgCommit *commit)
+update_index (GitgCommit *commit)
{
- runner_connect(commit, NULL, G_CALLBACK(update_index_end));
- gitg_repository_run_commandv(commit->priv->repository, commit->priv->runner, NULL, "update-index", "-q", "--unmerged", "--ignore-missing", "--refresh", NULL);
+ shell_connect (commit,
+ NULL,
+ G_CALLBACK (update_index_end));
+
+ gitg_shell_run (commit->priv->shell,
+ gitg_command_newv (commit->priv->repository,
+ "update-index",
+ "-q",
+ "--unmerged",
+ "--ignore-missing",
+ "--refresh",
+ NULL),
+ NULL);
}
static void
-set_can_delete(GFile *key, GitgChangedFile *value, GitgCommit *commit)
+set_can_delete (GFile *key,
+ GitgChangedFile *value,
+ GitgCommit *commit)
{
- g_object_set_data(G_OBJECT(value), CAN_DELETE_KEY, GINT_TO_POINTER(TRUE));
- gitg_changed_file_set_changes(value, GITG_CHANGED_FILE_CHANGES_NONE);
+ g_object_set_data (G_OBJECT (value),
+ CAN_DELETE_KEY,
+ GINT_TO_POINTER (TRUE));
+
+ gitg_changed_file_set_changes (value, GITG_CHANGED_FILE_CHANGES_NONE);
}
void
-gitg_commit_refresh(GitgCommit *commit)
+gitg_commit_refresh (GitgCommit *commit)
{
- g_return_if_fail(GITG_IS_COMMIT(commit));
+ g_return_if_fail (GITG_IS_COMMIT (commit));
- runner_cancel(commit);
+ shell_cancel (commit);
- g_hash_table_foreach(commit->priv->files, (GHFunc)set_can_delete, commit);
+ g_hash_table_foreach (commit->priv->files, (GHFunc)set_can_delete, commit);
/* Read other files */
if (commit->priv->repository)
- update_index(commit);
+ {
+ update_index (commit);
+ }
else
- refresh_done(commit->priv->runner, FALSE, commit);
+ {
+ refresh_done (commit->priv->shell, FALSE, commit);
+ }
}
static void
-update_index_staged(GitgCommit *commit, GitgChangedFile *file)
+update_index_staged (GitgCommit *commit,
+ GitgChangedFile *file)
{
- GFile *f = gitg_changed_file_get_file(file);
- gchar *path = gitg_repository_relative(commit->priv->repository, f);
- gchar *head = gitg_repository_parse_head(commit->priv->repository);
-
- gchar **ret = gitg_repository_command_with_outputv(commit->priv->repository, NULL, "diff-index", "--cached", head, "--", path, NULL);
+ GFile *f = gitg_changed_file_get_file (file);
+ gchar *path = gitg_repository_relative (commit->priv->repository, f);
+ gchar *head = gitg_repository_parse_head (commit->priv->repository);
+
+ gchar **ret = gitg_shell_run_sync_with_output (gitg_command_newv (commit->priv->repository,
+ "diff-index",
+ "--no-ext-diff",
+ "--cached",
+ head,
+ "--",
+ path,
+ NULL),
+ FALSE,
+ NULL);
- g_free(path);
- g_free(head);
- g_object_unref(f);
+ g_free (path);
+ g_free (head);
+ g_object_unref (f);
if (!ret)
+ {
return;
+ }
- gchar **parts = *ret ? g_strsplit_set(*ret, " \t", 0) : NULL;
- g_strfreev(ret);
+ gchar **parts = *ret ? g_strsplit_set (*ret, " \t", 0) : NULL;
+ g_strfreev (ret);
- if (parts && g_strv_length(parts) > 2)
+ if (parts && g_strv_length (parts) > 2)
{
- gitg_changed_file_set_mode(file, parts[0] + 1);
- gitg_changed_file_set_sha(file, parts[2]);
+ gitg_changed_file_set_mode (file, parts[0] + 1);
+ gitg_changed_file_set_sha (file, parts[2]);
- gitg_changed_file_set_changes(file, gitg_changed_file_get_changes(file) | GITG_CHANGED_FILE_CHANGES_CACHED);
- update_changed_file_status(file, parts[4], parts[0] + 1);
+ gitg_changed_file_set_changes (file,
+ gitg_changed_file_get_changes (file) |
+ GITG_CHANGED_FILE_CHANGES_CACHED);
+
+ update_changed_file_status (file, parts[4], parts[0] + 1);
}
else
{
- gitg_changed_file_set_changes(file, gitg_changed_file_get_changes(file) & ~GITG_CHANGED_FILE_CHANGES_CACHED);
+ gitg_changed_file_set_changes (file,
+ gitg_changed_file_get_changes (file) &
+ ~GITG_CHANGED_FILE_CHANGES_CACHED);
}
if (parts)
- g_strfreev(parts);
+ {
+ g_strfreev (parts);
+ }
}
static void
-update_index_unstaged(GitgCommit *commit, GitgChangedFile *file)
+update_index_unstaged (GitgCommit *commit,
+ GitgChangedFile *file)
{
- GFile *f = gitg_changed_file_get_file(file);
- gchar *path = gitg_repository_relative(commit->priv->repository, f);
- gchar **ret = gitg_repository_command_with_outputv(commit->priv->repository, NULL, "diff-files", "--", path, NULL);
- g_free(path);
- g_object_unref(f);
+ GFile *f = gitg_changed_file_get_file (file);
+ gchar *path = gitg_repository_relative (commit->priv->repository, f);
+ gchar **ret;
+
+ ret = gitg_shell_run_sync_with_output (gitg_command_newv (commit->priv->repository,
+ "diff-files",
+ "--no-ext-diff",
+ "--",
+ path,
+ NULL),
+ FALSE,
+ NULL);
+
+ g_free (path);
+ g_object_unref (f);
if (ret && *ret)
{
- gitg_changed_file_set_changes(file, gitg_changed_file_get_changes(file) | GITG_CHANGED_FILE_CHANGES_UNSTAGED);
+ gitg_changed_file_set_changes (file,
+ gitg_changed_file_get_changes (file) |
+ GITG_CHANGED_FILE_CHANGES_UNSTAGED);
}
else
{
- gitg_changed_file_set_changes(file, gitg_changed_file_get_changes(file) & ~GITG_CHANGED_FILE_CHANGES_UNSTAGED);
+ gitg_changed_file_set_changes (file,
+ gitg_changed_file_get_changes (file) &
+ ~GITG_CHANGED_FILE_CHANGES_UNSTAGED);
}
if (ret)
- g_strfreev(ret);
+ {
+ g_strfreev (ret);
+ }
}
static void
-update_index_file(GitgCommit *commit, GitgChangedFile *file)
+update_index_file (GitgCommit *commit,
+ GitgChangedFile *file)
{
/* update the index */
- GFile *f = gitg_changed_file_get_file(file);
- gchar *path = gitg_repository_relative(commit->priv->repository, f);
- g_object_unref(f);
+ GFile *f = gitg_changed_file_get_file (file);
+ gchar *path = gitg_repository_relative (commit->priv->repository, f);
+ g_object_unref (f);
- gitg_repository_commandv(commit->priv->repository, NULL, "update-index", "-q", "--unmerged", "--ignore-missing", "--refresh", NULL);
+ gitg_shell_run_sync (gitg_command_newv (commit->priv->repository,
+ "update-index",
+ "-q",
+ "--unmerged",
+ "--ignore-missing",
+ "--refresh",
+ NULL),
+ NULL);
- g_free(path);
+ g_free (path);
}
static void
-refresh_changes(GitgCommit *commit, GitgChangedFile *file)
+refresh_changes (GitgCommit *commit, GitgChangedFile *file)
{
/* update the index */
- update_index_file(commit, file);
+ update_index_file (commit, file);
/* Determine if it still has staged/unstaged changes */
- update_index_staged(commit, file);
- update_index_unstaged(commit, file);
+ update_index_staged (commit, file);
+ update_index_unstaged (commit, file);
- GitgChangedFileChanges changes = gitg_changed_file_get_changes(file);
- GitgChangedFileStatus status = gitg_changed_file_get_status(file);
+ GitgChangedFileChanges changes = gitg_changed_file_get_changes (file);
+ GitgChangedFileStatus status = gitg_changed_file_get_status (file);
- if (changes == GITG_CHANGED_FILE_CHANGES_NONE && status == GITG_CHANGED_FILE_CHANGES_NONE)
- gitg_changed_file_set_status(file, GITG_CHANGED_FILE_STATUS_NEW);
- else if ((changes & GITG_CHANGED_FILE_CHANGES_CACHED) && (changes & GITG_CHANGED_FILE_CHANGES_UNSTAGED))
- gitg_changed_file_set_status(file, GITG_CHANGED_FILE_STATUS_MODIFIED);
+ if (changes == GITG_CHANGED_FILE_CHANGES_NONE &&
+ status == GITG_CHANGED_FILE_CHANGES_NONE)
+ {
+ gitg_changed_file_set_status (file,
+ GITG_CHANGED_FILE_STATUS_NEW);
+ }
+ else if ((changes & GITG_CHANGED_FILE_CHANGES_CACHED) &&
+ (changes & GITG_CHANGED_FILE_CHANGES_UNSTAGED))
+ {
+ gitg_changed_file_set_status (file,
+ GITG_CHANGED_FILE_STATUS_MODIFIED);
+ }
if (status == GITG_CHANGED_FILE_STATUS_NEW &&
- !(changes & GITG_CHANGED_FILE_CHANGES_CACHED))
+ ! (changes & GITG_CHANGED_FILE_CHANGES_CACHED))
{
- gitg_changed_file_set_changes(file, GITG_CHANGED_FILE_CHANGES_UNSTAGED);
+ gitg_changed_file_set_changes (file,
+ GITG_CHANGED_FILE_CHANGES_UNSTAGED);
}
}
static gboolean
-apply_hunk (GitgCommit *commit,
- GitgChangedFile *file,
- gchar const *hunk,
- gboolean reverse,
- GError **error)
+apply_hunk (GitgCommit *commit,
+ GitgChangedFile *file,
+ gchar const *hunk,
+ gboolean reverse,
+ GError **error)
{
- g_return_val_if_fail (GITG_IS_COMMIT(commit), FALSE);
- g_return_val_if_fail (GITG_IS_CHANGED_FILE(file), FALSE);
+ g_return_val_if_fail (GITG_IS_COMMIT (commit), FALSE);
+ g_return_val_if_fail (GITG_IS_CHANGED_FILE (file), FALSE);
g_return_val_if_fail (hunk != NULL, FALSE);
- gboolean ret = gitg_repository_command_with_inputv (commit->priv->repository,
- hunk,
- error,
- "apply",
- "--cached",
- reverse ? "--reverse" : NULL,
- NULL);
+ gboolean ret = gitg_shell_run_sync_with_input (gitg_command_newv (commit->priv->repository,
+ "apply",
+ "--cached",
+ reverse ? "--reverse" : NULL,
+ NULL),
+ hunk,
+ error);
if (ret)
- refresh_changes(commit, file);
+ {
+ refresh_changes (commit, file);
+ }
return ret;
}
gboolean
-gitg_commit_stage(GitgCommit *commit, GitgChangedFile *file, gchar const *hunk, GError **error)
+gitg_commit_stage (GitgCommit *commit,
+ GitgChangedFile *file,
+ gchar const *hunk,
+ GError **error)
{
if (hunk)
- return apply_hunk(commit, file, hunk, FALSE, error);
+ {
+ return apply_hunk (commit, file, hunk, FALSE, error);
+ }
/* Otherwise, stage whole file */
- GFile *f = gitg_changed_file_get_file(file);
- gchar *path = gitg_repository_relative(commit->priv->repository, f);
- g_object_unref(f);
+ GFile *f = gitg_changed_file_get_file (file);
+ gchar *path = gitg_repository_relative (commit->priv->repository, f);
+ g_object_unref (f);
- gboolean ret = gitg_repository_commandv(commit->priv->repository, NULL, "update-index", "--add", "--remove", "--", path, NULL);
- g_free(path);
+ gboolean ret = gitg_shell_run_sync (gitg_command_newv (commit->priv->repository,
+ "update-index",
+ "--add",
+ "--remove",
+ "--",
+ path,
+ NULL),
+ error);
+ g_free (path);
if (ret)
- refresh_changes(commit, file);
+ {
+ refresh_changes (commit, file);
+ }
else
- g_error("Update index for stage failed");
+ {
+ g_error ("Update index for stage failed");
+ }
return ret;
}
gboolean
-gitg_commit_unstage(GitgCommit *commit, GitgChangedFile *file, gchar const *hunk, GError **error)
+gitg_commit_unstage (GitgCommit *commit,
+ GitgChangedFile *file,
+ gchar const *hunk,
+ GError **error)
{
if (hunk)
- return apply_hunk(commit, file, hunk, TRUE, error);
+ {
+ return apply_hunk (commit, file, hunk, TRUE, error);
+ }
/* Otherwise, unstage whole file */
- GFile *f = gitg_changed_file_get_file(file);
- gchar *path = gitg_repository_relative(commit->priv->repository, f);
- g_object_unref(f);
+ GFile *f = gitg_changed_file_get_file (file);
+ gchar *path = gitg_repository_relative (commit->priv->repository, f);
+ g_object_unref (f);
- gchar *input = g_strdup_printf("%s %s\t%s\n", gitg_changed_file_get_mode(file), gitg_changed_file_get_sha(file), path);
- gboolean ret = gitg_repository_command_with_inputv(commit->priv->repository, input, error, "update-index", "--index-info", NULL);
- g_free(input);
+ gchar *input = g_strdup_printf ("%s %s\t%s\n",
+ gitg_changed_file_get_mode (file),
+ gitg_changed_file_get_sha (file),
+ path);
+
+ gboolean ret = gitg_shell_run_sync_with_input (gitg_command_newv (commit->priv->repository,
+ "update-index",
+ "--index-info",
+ NULL),
+ input,
+ error);
+
+ g_free (input);
if (ret)
- refresh_changes(commit, file);
+ {
+ refresh_changes (commit, file);
+ }
else
- g_error("Update index for unstage failed");
+ {
+ g_error ("Update index for unstage failed");
+ }
return ret;
}
static void
-find_staged(GFile *key, GitgChangedFile *value, gboolean *result)
+find_staged (GFile *key,
+ GitgChangedFile *value,
+ gboolean *result)
{
if (*result)
+ {
return;
+ }
- *result = (gitg_changed_file_get_changes(value) & GITG_CHANGED_FILE_CHANGES_CACHED);
+ *result = (gitg_changed_file_get_changes (value) &
+ GITG_CHANGED_FILE_CHANGES_CACHED);
}
gboolean
-gitg_commit_has_changes(GitgCommit *commit)
+gitg_commit_has_changes (GitgCommit *commit)
{
- g_return_val_if_fail(GITG_IS_COMMIT(commit), FALSE);
+ g_return_val_if_fail (GITG_IS_COMMIT (commit), FALSE);
gboolean result = FALSE;
- g_hash_table_foreach(commit->priv->files, (GHFunc)find_staged, &result);
+ g_hash_table_foreach (commit->priv->files, (GHFunc)find_staged, &result);
return result;
}
static gchar *
-comment_parse_subject(gchar const *comment)
+comment_parse_subject (gchar const *comment)
{
gchar *ptr;
gchar *subject;
- if ((ptr = g_utf8_strchr(comment, g_utf8_strlen(comment, -1), '\n')) != NULL)
+ if ((ptr = g_utf8_strchr (comment, g_utf8_strlen (comment, -1), '\n')) != NULL)
{
- subject = g_strndup(comment, ptr - comment);
+ subject = g_strndup (comment, ptr - comment);
}
else
{
- subject = g_strdup(comment);
+ subject = g_strdup (comment);
}
- gchar *commit = g_strconcat("commit:", subject, NULL);
- g_free(subject);
+ gchar *commit = g_strconcat ("commit:", subject, NULL);
+ g_free (subject);
return commit;
}
static gboolean
-write_tree(GitgCommit *commit, gchar **tree, GError **error)
+write_tree (GitgCommit *commit, gchar **tree, GError **error)
{
- gchar const *argv[] = {"write-tree", NULL};
- gchar **lines = gitg_repository_command_with_output(commit->priv->repository, argv, error);
+ gchar **lines = gitg_shell_run_sync_with_output (gitg_command_newv (commit->priv->repository,
+ "write-tree",
+ NULL),
+ FALSE,
+ error);
- if (!lines || strlen(*lines) != GITG_HASH_SHA_SIZE)
+ if (!lines || strlen (*lines) != GITG_HASH_SHA_SIZE)
{
- g_strfreev(lines);
+ g_strfreev (lines);
return FALSE;
}
- *tree = g_strdup(*lines);
- g_strfreev(lines);
+ *tree = g_strdup (*lines);
+ g_strfreev (lines);
return TRUE;
}
static gchar *
-get_signed_off_line(GitgCommit *commit)
+get_signed_off_line (GitgCommit *commit)
{
- gchar **user = gitg_repository_command_with_outputv(commit->priv->repository, NULL, "config", "--get", "user.name", NULL);
+ gchar **user = gitg_shell_run_sync_with_output (gitg_command_newv (commit->priv->repository,
+ "config",
+ "--get",
+ "user.name",
+ NULL),
+ FALSE,
+ NULL);
if (!user)
+ {
return NULL;
+ }
if (!*user || !**user)
{
- g_strfreev(user);
+ g_strfreev (user);
return NULL;
}
- gchar **email = gitg_repository_command_with_outputv(commit->priv->repository, NULL, "config", "--get", "user.email", NULL);
+ gchar **email = gitg_shell_run_sync_with_output (gitg_command_newv (commit->priv->repository,
+ "config",
+ "--get",
+ "user.email",
+ NULL),
+ FALSE,
+ NULL);
if (!email)
{
- g_strfreev(user);
+ g_strfreev (user);
return NULL;
}
if (!*email || !**email)
{
- g_strfreev(user);
- g_strfreev(email);
+ g_strfreev (user);
+ g_strfreev (email);
return NULL;
}
- gchar *ret = g_strdup_printf("Signed-off-by: %s <%s>", *user, *email);
- g_strfreev(user);
- g_strfreev(email);
+ gchar *ret = g_strdup_printf ("Signed-off-by: %s <%s>", *user, *email);
+ g_strfreev (user);
+ g_strfreev (email);
return ret;
}
static void
-on_commit_tree_update (GitgRunner *runner, gchar **lines, GString *buffer)
-{
- while (lines && *lines)
- {
- if (buffer->len != 0)
- {
- g_string_append_c (buffer, '\n');
- }
-
- g_string_append (buffer, *lines);
- ++lines;
- }
-}
-
-static void
-set_amend_environment (GitgCommit *commit, GitgRunner *runner)
+set_amend_environment (GitgCommit *commit,
+ GitgCommand *command)
{
gchar **out;
- out = gitg_repository_command_with_outputv (commit->priv->repository,
- NULL,
- "cat-file",
- "commit",
- "HEAD",
- NULL);
+ out = gitg_shell_run_sync_with_output (gitg_command_newv (commit->priv->repository,
+ "cat-file",
+ "commit",
+ "HEAD",
+ NULL),
+ FALSE,
+ NULL);
// Parse author
- GRegex *r = g_regex_new ("^author (.*) <([^>]*)> ([0-9]+.*)$",
+ GRegex *r = g_regex_new ("^author (.*) < ([^>]*)> ([0-9]+.*)$",
G_REGEX_CASELESS,
0,
NULL);
@@ -766,9 +985,9 @@ set_amend_environment (GitgCommit *commit, GitgRunner *runner)
gchar *email = g_match_info_fetch (info, 2);
gchar *date = g_match_info_fetch (info, 3);
- gitg_runner_add_environment (runner, "GIT_AUTHOR_NAME", name);
- gitg_runner_add_environment (runner, "GIT_AUTHOR_EMAIL", email);
- gitg_runner_add_environment (runner, "GIT_AUTHOR_DATE", date);
+ gitg_command_add_environmentv (command, "GIT_AUTHOR_NAME", name, NULL);
+ gitg_command_add_environmentv (command, "GIT_AUTHOR_EMAIL", email, NULL);
+ gitg_command_add_environmentv (command, "GIT_AUTHOR_DATE", date, NULL);
g_free (name);
g_free (email);
@@ -784,7 +1003,8 @@ set_amend_environment (GitgCommit *commit, GitgRunner *runner)
}
static gchar *
-convert_commit_encoding (GitgCommit *commit, gchar const *s)
+convert_commit_encoding (GitgCommit *commit,
+ gchar const *s)
{
GitgConfig *config;
gchar *encoding;
@@ -824,98 +1044,129 @@ convert_commit_encoding (GitgCommit *commit, gchar const *s)
return ret;
}
-static gboolean
-commit_tree(GitgCommit *commit, gchar const *tree, gchar const *comment, gboolean signoff, gboolean amend, gchar **ref, GError **error)
+static gboolean
+commit_tree (GitgCommit *commit,
+ gchar const *tree,
+ gchar const *comment,
+ gboolean signoff,
+ gboolean amend,
+ gchar **ref,
+ GError **error)
{
gchar *fullcomment;
if (signoff)
{
- gchar *line = get_signed_off_line(commit);
+ gchar *line = get_signed_off_line (commit);
if (!line)
{
if (error)
- g_set_error(error, GITG_COMMIT_ERROR, GITG_COMMIT_ERROR_SIGNOFF, "Could not retrieve user name or email for signoff message");
+ {
+ g_set_error (error,
+ GITG_COMMIT_ERROR,
+ GITG_COMMIT_ERROR_SIGNOFF,
+ "Could not retrieve user name or email for signoff message");
+ }
return FALSE;
}
- fullcomment = g_strconcat(comment, "\n\n", line, NULL);
+ fullcomment = g_strconcat (comment, "\n\n", line, NULL);
}
else
{
- fullcomment = g_strdup(comment);
+ fullcomment = g_strdup (comment);
}
gchar *head;
if (amend)
{
- head = gitg_repository_parse_ref(commit->priv->repository, "HEAD^");
+ head = gitg_repository_parse_ref (commit->priv->repository,
+ "HEAD^");
}
else
{
- head = gitg_repository_parse_ref(commit->priv->repository, "HEAD");
+ head = gitg_repository_parse_ref (commit->priv->repository,
+ "HEAD");
}
- GitgRunner *runner = gitg_runner_new_synchronized (1000);
- GString *buffer = g_string_new ("");
+ GitgCommand *command;
+ gchar **buffer;
+
+ command = gitg_command_newv (commit->priv->repository,
+ "commit-tree",
+ tree,
+ head ? "-p" : NULL,
+ head,
+ NULL);
if (amend)
{
- set_amend_environment (commit, runner);
+ set_amend_environment (commit, command);
}
gchar *converted = convert_commit_encoding (commit, fullcomment);
- g_signal_connect (runner, "update", G_CALLBACK (on_commit_tree_update), buffer);
- gitg_repository_run_command_with_inputv (commit->priv->repository,
- runner,
- converted,
- error,
- "commit-tree",
- tree,
- head ? "-p" : NULL,
- head,
- NULL);
-
- g_free(head);
- g_free(fullcomment);
- g_free(converted);
- g_object_unref (runner);
-
- if (buffer->len != GITG_HASH_SHA_SIZE)
+ buffer = gitg_shell_run_sync_with_input_and_output (command,
+ FALSE,
+ converted,
+ error);
+
+ g_free (head);
+ g_free (fullcomment);
+ g_free (converted);
+ g_object_unref (command);
+
+ if (!buffer || !*buffer || strlen (*buffer) != GITG_HASH_SHA_SIZE)
{
- g_string_free(buffer, TRUE);
+ g_strfreev (buffer);
return FALSE;
}
- *ref = g_string_free (buffer, FALSE);
+ *ref = g_strdup (*buffer);
+ g_strfreev (buffer);
+
return TRUE;
}
static gboolean
-update_ref(GitgCommit *commit, gchar const *ref, gchar const *subject, GError **error)
+update_ref (GitgCommit *commit,
+ gchar const *ref,
+ gchar const *subject,
+ GError **error)
{
gchar *converted = convert_commit_encoding (commit, subject);
- gchar const *argv[] = {"update-ref", "-m", converted, "HEAD", ref, NULL};
- gboolean ret = gitg_repository_command(commit->priv->repository, argv, error);
+ gboolean ret = gitg_shell_run_sync (gitg_command_newv (commit->priv->repository,
+ "update-ref",
+ "-m",
+ converted,
+ "HEAD",
+ ref,
+ NULL),
+ error);
g_free (converted);
return ret;
}
gboolean
-gitg_commit_commit(GitgCommit *commit, gchar const *comment, gboolean signoff, gboolean amend, GError **error)
+gitg_commit_commit (GitgCommit *commit,
+ gchar const *comment,
+ gboolean signoff,
+ gboolean amend,
+ GError **error)
{
- g_return_val_if_fail(GITG_IS_COMMIT(commit), FALSE);
+ g_return_val_if_fail (GITG_IS_COMMIT (commit), FALSE);
gchar *tree;
- if (!write_tree(commit, &tree, error))
+ if (!write_tree (commit, &tree, error))
+ {
return FALSE;
+ }
GFile *git_dir = gitg_repository_get_git_dir (commit->priv->repository);
GFile *child = g_file_get_child (git_dir, "COMMIT_EDITMSG");
@@ -928,86 +1179,117 @@ gitg_commit_commit(GitgCommit *commit, gchar const *comment, gboolean signoff, g
g_free (path);
gchar *ref;
- gboolean ret = commit_tree(commit, tree, comment, signoff, amend, &ref, error);
- g_free(tree);
+ gboolean ret = commit_tree (commit, tree, comment, signoff, amend, &ref, error);
+ g_free (tree);
if (!ret)
+ {
return FALSE;
+ }
- gchar *subject = comment_parse_subject(comment);
- ret = update_ref(commit, ref, subject, error);
- g_free(subject);
+ gchar *subject = comment_parse_subject (comment);
+ ret = update_ref (commit, ref, subject, error);
+ g_free (subject);
if (!ret)
+ {
return FALSE;
+ }
- gitg_repository_reload(commit->priv->repository);
+ gitg_repository_reload (commit->priv->repository);
return TRUE;
}
static void
-remove_file(GitgCommit *commit, GitgChangedFile *file)
+remove_file (GitgCommit *commit,
+ GitgChangedFile *file)
{
- GFile *f = gitg_changed_file_get_file(file);
+ GFile *f = gitg_changed_file_get_file (file);
- g_hash_table_remove(commit->priv->files, f);
- g_object_unref(f);
+ g_hash_table_remove (commit->priv->files, f);
+ g_object_unref (f);
+
+ g_signal_emit (commit, commit_signals[REMOVED], 0, file);
+}
- g_signal_emit(commit, commit_signals[REMOVED], 0, file);
+gboolean
+gitg_commit_revert (GitgCommit *commit,
+ GitgRevision *from,
+ GitgRevision *to,
+ GError **error)
+{
+ g_return_val_if_fail (GITG_IS_COMMIT (commit), FALSE);
+ g_return_val_if_fail (from != NULL, FALSE);
+ g_return_val_if_fail (to != NULL, FALSE);
+
+ return FALSE;
+
+ // TODO
+ /*gchar *sha1from = gitg_revision_get_sha1 (from);
+ gchar *sha1to = gitg_revision_get_sha1 (to);
+
+ gitg_repository_command_with_outputv (commit->priv->repository,
+ error,
+ "diff",
+ "--full-index",
+ "--binary",
+ "--no-color",
+ sha1to,
+ sha1from,
+ NULL)
+ git diff --full-index --binary --no-color to from*/
}
gboolean
-gitg_commit_revert(GitgCommit *commit, GitgChangedFile *file, gchar const *hunk, GError **error)
+gitg_commit_undo (GitgCommit *commit,
+ GitgChangedFile *file,
+ gchar const *hunk,
+ GError **error)
{
gboolean ret;
if (!hunk)
{
- GFile *f = gitg_changed_file_get_file(file);
- gchar *path = gitg_repository_relative(commit->priv->repository, f);
-
- ret = gitg_repository_command_with_inputv (commit->priv->repository,
- path,
- error,
- "checkout-index",
- "--index",
- "--quiet",
- "--force",
- "--stdin",
- NULL);
-
- g_free(path);
-
- update_index_file(commit, file);
- update_index_unstaged(commit, file);
- g_object_unref(f);
+ GFile *f = gitg_changed_file_get_file (file);
+ gchar *path = gitg_repository_relative (commit->priv->repository, f);
+
+ ret = gitg_shell_run_sync_with_input (gitg_command_newv (commit->priv->repository,
+ "checkout-index",
+ "--index",
+ "--quiet",
+ "--force",
+ "--stdin",
+ NULL),
+ path,
+ error);
+
+ g_free (path);
+
+ update_index_file (commit, file);
+ update_index_unstaged (commit, file);
+ g_object_unref (f);
}
else
{
- GitgRunner *runner = gitg_runner_new_synchronized(1000);
- gchar const *argv[] = {"patch", "-p1", "-R", NULL};
-
- GFile *work_tree = gitg_repository_get_work_tree (commit->priv->repository);
-
- ret = gitg_runner_run_with_arguments (runner,
- work_tree,
- argv,
+ ret = gitg_shell_run_sync_with_input (gitg_command_newv (commit->priv->repository,
+ "apply",
+ "-R",
+ "-",
+ NULL),
hunk,
- NULL);
-
- g_object_unref (work_tree);
-
- update_index_file(commit, file);
- update_index_unstaged(commit, file);
+ error);
- g_object_unref(runner);
+ update_index_file (commit, file);
+ update_index_unstaged (commit, file);
}
return ret;
}
gboolean
-gitg_commit_add_ignore (GitgCommit *commit, GitgChangedFile *file, GError **error)
+gitg_commit_add_ignore (GitgCommit *commit,
+ GitgChangedFile *file,
+ GError **error)
{
g_return_val_if_fail (GITG_IS_COMMIT (commit), FALSE);
g_return_val_if_fail (GITG_IS_CHANGED_FILE (file), FALSE);
@@ -1018,7 +1300,10 @@ gitg_commit_add_ignore (GitgCommit *commit, GitgChangedFile *file, GError **erro
GFile *git_dir = gitg_repository_get_work_tree (commit->priv->repository);
GFile *ignore = g_file_get_child (git_dir, ".gitignore");
- GFileOutputStream *stream = g_file_append_to (ignore, G_FILE_CREATE_NONE, NULL, error);
+ GFileOutputStream *stream = g_file_append_to (ignore,
+ G_FILE_CREATE_NONE,
+ NULL,
+ error);
gboolean ret = FALSE;
g_object_unref (git_dir);
@@ -1026,7 +1311,7 @@ gitg_commit_add_ignore (GitgCommit *commit, GitgChangedFile *file, GError **erro
if (stream)
{
- gchar *line = g_strdup_printf("/%s\n", path);
+ gchar *line = g_strdup_printf ("/%s\n", path);
ret = g_output_stream_write_all (G_OUTPUT_STREAM (stream),
line,
@@ -1042,7 +1327,9 @@ gitg_commit_add_ignore (GitgCommit *commit, GitgChangedFile *file, GError **erro
}
if (ret)
+ {
remove_file (commit, file);
+ }
g_object_unref (f);
g_free (path);
@@ -1051,22 +1338,24 @@ gitg_commit_add_ignore (GitgCommit *commit, GitgChangedFile *file, GError **erro
}
static void
-on_changed_file_changed(GitgChangedFile *file, GitgCommit *commit)
+on_changed_file_changed (GitgChangedFile *file,
+ GitgCommit *commit)
{
- refresh_changes(commit, file);
+ refresh_changes (commit, file);
}
GitgChangedFile *
-gitg_commit_find_changed_file(GitgCommit *commit, GFile *file)
+gitg_commit_find_changed_file (GitgCommit *commit,
+ GFile *file)
{
- g_return_val_if_fail(GITG_IS_COMMIT(commit), NULL);
- g_return_val_if_fail(G_IS_FILE(file), NULL);
+ g_return_val_if_fail (GITG_IS_COMMIT (commit), NULL);
+ g_return_val_if_fail (G_IS_FILE (file), NULL);
- GitgChangedFile *f = g_hash_table_lookup(commit->priv->files, file);
+ GitgChangedFile *f = g_hash_table_lookup (commit->priv->files, file);
if (f != NULL)
{
- return g_object_ref(f);
+ return g_object_ref (f);
}
else
{
@@ -1081,12 +1370,13 @@ gitg_commit_amend_message (GitgCommit *commit)
gchar **out;
- out = gitg_repository_command_with_outputv (commit->priv->repository,
- NULL,
- "cat-file",
- "commit",
- "HEAD",
- NULL);
+ out = gitg_shell_run_sync_with_output (gitg_command_newv (commit->priv->repository,
+ "cat-file",
+ "commit",
+ "HEAD",
+ NULL),
+ FALSE,
+ NULL);
gchar *ret = NULL;
diff --git a/libgitg/gitg-commit.h b/libgitg/gitg-commit.h
index 27e2587..66a62d1 100644
--- a/libgitg/gitg-commit.h
+++ b/libgitg/gitg-commit.h
@@ -46,7 +46,8 @@ typedef struct _GitgCommitPrivate GitgCommitPrivate;
typedef enum
{
GITG_COMMIT_ERROR_NONE = 0,
- GITG_COMMIT_ERROR_SIGNOFF
+ GITG_COMMIT_ERROR_SIGNOFF,
+ GITG_COMMIT_ERROR_MERGE
} GitgCommitError;
struct _GitgCommit {
@@ -62,24 +63,45 @@ struct _GitgCommitClass {
void (*removed) (GitgCommit *commit, GitgChangedFile *file);
};
-GQuark gitg_commit_error_quark(void);
-
-GType gitg_commit_get_type(void) G_GNUC_CONST;
-GitgCommit *gitg_commit_new(GitgRepository *repository);
-
-void gitg_commit_refresh(GitgCommit *commit);
-gboolean gitg_commit_stage(GitgCommit *commit, GitgChangedFile *file, gchar const *hunk, GError **error);
-gboolean gitg_commit_unstage(GitgCommit *commit, GitgChangedFile *file, gchar const *hunk, GError **error);
-
-gboolean gitg_commit_has_changes(GitgCommit *commit);
-gboolean gitg_commit_commit(GitgCommit *commit, gchar const *comment, gboolean signoff, gboolean amend, GError **error);
-
-gboolean gitg_commit_revert(GitgCommit *commit, GitgChangedFile *file, gchar const *hunk, GError **error);
-gboolean gitg_commit_add_ignore(GitgCommit *commit, GitgChangedFile *file, GError **error);
-
-GitgChangedFile *gitg_commit_find_changed_file(GitgCommit *commit, GFile *file);
-
-gchar *gitg_commit_amend_message (GitgCommit *commit);
+GQuark gitg_commit_error_quark (void);
+
+GType gitg_commit_get_type (void) G_GNUC_CONST;
+GitgCommit *gitg_commit_new (GitgRepository *repository);
+
+void gitg_commit_refresh (GitgCommit *commit);
+gboolean gitg_commit_stage (GitgCommit *commit,
+ GitgChangedFile *file,
+ gchar const *hunk,
+ GError **error);
+gboolean gitg_commit_unstage (GitgCommit *commit,
+ GitgChangedFile *file,
+ gchar const *hunk,
+ GError **error);
+gboolean gitg_commit_has_changes (GitgCommit *commit);
+gboolean gitg_commit_commit (GitgCommit *commit,
+ gchar const *comment,
+ gboolean signoff,
+ gboolean amend,
+ GError **error);
+
+gboolean gitg_commit_revert (GitgCommit *commit,
+ GitgRevision *from,
+ GitgRevision *to,
+ GError **error);
+
+gboolean gitg_commit_undo (GitgCommit *commit,
+ GitgChangedFile *file,
+ gchar const *hunk,
+ GError **error);
+
+gboolean gitg_commit_add_ignore (GitgCommit *commit,
+ GitgChangedFile *file,
+ GError **error);
+
+GitgChangedFile *gitg_commit_find_changed_file (GitgCommit *commit,
+ GFile *file);
+
+gchar *gitg_commit_amend_message (GitgCommit *commit);
G_END_DECLS
diff --git a/libgitg/gitg-config.c b/libgitg/gitg-config.c
index 8a8b30a..e0e5934 100644
--- a/libgitg/gitg-config.c
+++ b/libgitg/gitg-config.c
@@ -21,7 +21,7 @@
*/
#include "gitg-config.h"
-
+#include "gitg-shell.h"
#define GITG_CONFIG_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE((object), GITG_TYPE_CONFIG, GitgConfigPrivate))
@@ -34,7 +34,7 @@ enum
struct _GitgConfigPrivate
{
GitgRepository *repository;
- GitgRunner *runner;
+ GitgShell *shell;
GString *accumulated;
};
@@ -113,24 +113,22 @@ gitg_config_class_init (GitgConfigClass *klass)
}
static void
-gitg_config_accumulate (GitgRunner *runner, gchar **buffer, GitgConfig *config)
+gitg_config_accumulate (GitgShell *shell,
+ gchar **buffer,
+ GitgConfig *config)
{
gchar **ptr = buffer;
while (*ptr)
{
- if (config->priv->accumulated->len != 0)
- {
- g_string_append_c (config->priv->accumulated, '\n');
- }
-
g_string_append (config->priv->accumulated, *ptr);
++ptr;
}
}
static void
-gitg_config_begin_loading (GitgRunner *runner, GitgConfig *config)
+gitg_config_begin (GitgShell *shell,
+ GitgConfig *config)
{
g_string_erase (config->priv->accumulated, 0, -1);
}
@@ -140,18 +138,18 @@ gitg_config_init (GitgConfig *self)
{
self->priv = GITG_CONFIG_GET_PRIVATE (self);
- self->priv->runner = gitg_runner_new_synchronized (1000);
+ self->priv->shell = gitg_shell_new_synchronized (1000);
self->priv->accumulated = g_string_new ("");
- g_signal_connect (self->priv->runner,
- "update",
+ g_signal_connect (self->priv->shell,
+ "update",
G_CALLBACK (gitg_config_accumulate),
self);
- g_signal_connect (self->priv->runner,
- "begin-loading",
- G_CALLBACK (gitg_config_begin_loading),
+ g_signal_connect (self->priv->shell,
+ "begin",
+ G_CALLBACK (gitg_config_begin),
self);
}
@@ -168,7 +166,8 @@ get_value_process (GitgConfig *config, gboolean ret)
if (ret)
{
- res = g_strndup (config->priv->accumulated->str, config->priv->accumulated->len);
+ res = g_strndup (config->priv->accumulated->str,
+ config->priv->accumulated->len);
}
else
{
@@ -181,15 +180,14 @@ get_value_process (GitgConfig *config, gboolean ret)
static gchar *
get_value_global (GitgConfig *config, gchar const *key)
{
- gchar const *argv[] = {
- "git",
- "config",
- "--global",
- key,
- NULL
- };
-
- gboolean ret = gitg_runner_run (config->priv->runner, argv, NULL);
+ gboolean ret = gitg_shell_run (config->priv->shell,
+ gitg_command_newv (config->priv->repository,
+ "config",
+ "--global",
+ key,
+ NULL),
+ NULL);
+
return get_value_process (config, ret);
}
@@ -198,17 +196,14 @@ get_value_global_regex (GitgConfig *config,
gchar const *regex,
gchar const *value_regex)
{
- gchar const *argv[] = {
- "git",
- "config",
- "--global",
- "--get-regexp",
- regex,
- value_regex,
- NULL
- };
-
- gboolean ret = gitg_runner_run (config->priv->runner, argv, NULL);
+ gboolean ret = gitg_shell_run (config->priv->shell,
+ gitg_command_newv (config->priv->repository,
+ "config",
+ "--global",
+ "--get-regexp",
+ NULL),
+ NULL);
+
return get_value_process (config, ret);
}
@@ -225,14 +220,14 @@ get_value_local (GitgConfig *config, gchar const *key)
cfg_file = g_file_get_child (git_dir, "config");
cfg = g_file_get_path (cfg_file);
- ret = gitg_repository_run_commandv (config->priv->repository,
- config->priv->runner,
- NULL,
- "config",
- "--file",
- cfg,
- key,
- NULL);
+ ret = gitg_shell_run (config->priv->shell,
+ gitg_command_newv (config->priv->repository,
+ "config",
+ "--file",
+ cfg,
+ key,
+ NULL),
+ NULL);
g_free (cfg);
@@ -257,16 +252,16 @@ get_value_local_regex (GitgConfig *config,
cfg_file = g_file_get_child (git_dir, "config");
cfg = g_file_get_path (cfg_file);
- ret = gitg_repository_run_commandv (config->priv->repository,
- config->priv->runner,
- NULL,
- "config",
- "--file",
- cfg,
- "--get-regexp",
- regex,
- value_regex,
- NULL);
+ ret = gitg_shell_run (config->priv->shell,
+ gitg_command_newv (config->priv->repository,
+ "config",
+ "--file",
+ cfg,
+ "--get-regexp",
+ regex,
+ value_regex,
+ NULL),
+ NULL);
g_free (cfg);
@@ -279,16 +274,14 @@ get_value_local_regex (GitgConfig *config,
static gboolean
set_value_global (GitgConfig *config, gchar const *key, gchar const *value)
{
- gchar const *argv[] = {
- "git",
- "config",
- "--global",
- value == NULL ? "--unset" : key,
- value == NULL ? key : value,
- NULL
- };
-
- return gitg_runner_run (config->priv->runner, argv, NULL);
+ return gitg_shell_run (config->priv->shell,
+ gitg_command_newv (config->priv->repository,
+ "config",
+ "--global",
+ value == NULL ? "--unset" : key,
+ value == NULL ? key : value,
+ NULL),
+ NULL);
}
static gboolean
@@ -304,15 +297,15 @@ set_value_local (GitgConfig *config, gchar const *key, gchar const *value)
cfg_file = g_file_get_child (git_dir, "config");
cfg = g_file_get_path (cfg_file);
- ret = gitg_repository_run_commandv (config->priv->repository,
- config->priv->runner,
- NULL,
- "config",
- "--file",
- cfg,
- value == NULL ? "--unset" : key,
- value == NULL ? key : value,
- NULL);
+ ret = gitg_shell_run (config->priv->shell,
+ gitg_command_newv (config->priv->repository,
+ "config",
+ "--file",
+ cfg,
+ value == NULL ? "--unset" : key,
+ value == NULL ? key : value,
+ NULL),
+ NULL);
g_free (cfg);
@@ -325,17 +318,15 @@ set_value_local (GitgConfig *config, gchar const *key, gchar const *value)
static gboolean
rename_global (GitgConfig *config, gchar const *old, gchar const *nw)
{
- gchar const *argv[] = {
- "git",
- "config",
- "--global",
- "--rename-section",
- old,
- nw,
- NULL
- };
-
- return gitg_runner_run (config->priv->runner, argv, NULL);
+ return gitg_shell_run (config->priv->shell,
+ gitg_command_newv (config->priv->repository,
+ "config",
+ "--global",
+ "--rename-section",
+ old,
+ nw,
+ NULL),
+ NULL);
}
static gboolean
@@ -351,16 +342,16 @@ rename_local (GitgConfig *config, gchar const *old, gchar const *nw)
cfg_file = g_file_get_child (git_dir, "config");
cfg = g_file_get_path (cfg_file);
- ret = gitg_repository_run_commandv (config->priv->repository,
- config->priv->runner,
- NULL,
- "config",
- "--file",
- cfg,
- "--rename-section",
- old,
- nw,
- NULL);
+ ret = gitg_shell_run (config->priv->shell,
+ gitg_command_newv (config->priv->repository,
+ "config",
+ "--file",
+ cfg,
+ "--rename-section",
+ old,
+ nw,
+ NULL),
+ NULL);
g_free (cfg);
diff --git a/libgitg/gitg-config.h b/libgitg/gitg-config.h
index 0fb61d0..a68363e 100644
--- a/libgitg/gitg-config.h
+++ b/libgitg/gitg-config.h
@@ -28,36 +28,47 @@
G_BEGIN_DECLS
-#define GITG_TYPE_CONFIG (gitg_config_get_type ())
-#define GITG_CONFIG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GITG_TYPE_CONFIG, GitgConfig))
+#define GITG_TYPE_CONFIG (gitg_config_get_type ())
+#define GITG_CONFIG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GITG_TYPE_CONFIG, GitgConfig))
#define GITG_CONFIG_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GITG_TYPE_CONFIG, GitgConfig const))
#define GITG_CONFIG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GITG_TYPE_CONFIG, GitgConfigClass))
-#define GITG_IS_CONFIG(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GITG_TYPE_CONFIG))
+#define GITG_IS_CONFIG(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GITG_TYPE_CONFIG))
#define GITG_IS_CONFIG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GITG_TYPE_CONFIG))
#define GITG_CONFIG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GITG_TYPE_CONFIG, GitgConfigClass))
-typedef struct _GitgConfig GitgConfig;
+typedef struct _GitgConfig GitgConfig;
typedef struct _GitgConfigClass GitgConfigClass;
typedef struct _GitgConfigPrivate GitgConfigPrivate;
-struct _GitgConfig {
+struct _GitgConfig
+{
GObject parent;
GitgConfigPrivate *priv;
};
-struct _GitgConfigClass {
+struct _GitgConfigClass
+{
GObjectClass parent_class;
};
-GType gitg_config_get_type (void) G_GNUC_CONST;
-GitgConfig *gitg_config_new (GitgRepository *repository);
+GType gitg_config_get_type (void) G_GNUC_CONST;
+GitgConfig *gitg_config_new (GitgRepository *repository);
-gchar *gitg_config_get_value (GitgConfig *config, gchar const *key);
-gchar *gitg_config_get_value_regex (GitgConfig *config, gchar const *regex, gchar const *value_regex);
+gchar *gitg_config_get_value (GitgConfig *config,
+ gchar const *key);
-gboolean gitg_config_rename (GitgConfig *config, gchar const *old, gchar const *nw);
-gboolean gitg_config_set_value (GitgConfig *config, gchar const *key, gchar const *value);
+gchar *gitg_config_get_value_regex (GitgConfig *config,
+ gchar const *regex,
+ gchar const *value_regex);
+
+gboolean gitg_config_rename (GitgConfig *config,
+ gchar const *old,
+ gchar const *nw);
+
+gboolean gitg_config_set_value (GitgConfig *config,
+ gchar const *key,
+ gchar const *value);
G_END_DECLS
diff --git a/libgitg/gitg-io.c b/libgitg/gitg-io.c
new file mode 100644
index 0000000..2300adb
--- /dev/null
+++ b/libgitg/gitg-io.c
@@ -0,0 +1,406 @@
+#include "gitg-io.h"
+
+
+#define GITG_IO_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE((object), GITG_TYPE_IO, GitgIOPrivate))
+
+struct _GitgIOPrivate
+{
+ GInputStream *input;
+ GOutputStream *output;
+
+ gint exit_status;
+
+ guint cancelled : 1;
+ guint running : 1;
+};
+
+enum
+{
+ PROP_0,
+
+ PROP_INPUT,
+ PROP_OUTPUT,
+ PROP_CANCELLED,
+ PROP_EXIT_STATUS,
+ PROP_RUNNING
+};
+
+enum
+{
+ BEGIN,
+ END,
+ NUM_SIGNALS
+};
+
+G_DEFINE_TYPE (GitgIO, gitg_io, G_TYPE_OBJECT)
+
+static guint signals[NUM_SIGNALS] = {0,};
+
+static void
+gitg_io_finalize (GObject *object)
+{
+ G_OBJECT_CLASS (gitg_io_parent_class)->finalize (object);
+}
+
+static void
+gitg_io_dispose (GObject *object)
+{
+ GitgIO *io;
+
+ io = GITG_IO (object);
+
+ gitg_io_close (io);
+
+ G_OBJECT_CLASS (gitg_io_parent_class)->dispose (object);
+}
+
+static void
+gitg_io_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GitgIO *self = GITG_IO (object);
+
+ switch (prop_id)
+ {
+ case PROP_INPUT:
+ gitg_io_set_input (self, g_value_get_object (value));
+ break;
+ case PROP_OUTPUT:
+ gitg_io_set_output (self, g_value_get_object (value));
+ break;
+ case PROP_CANCELLED:
+ gitg_io_set_cancelled (self, g_value_get_boolean (value));
+ break;
+ case PROP_EXIT_STATUS:
+ gitg_io_set_exit_status (self, g_value_get_int (value));
+ break;
+ case PROP_RUNNING:
+ gitg_io_set_running (self, g_value_get_boolean (value));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gitg_io_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GitgIO *self = GITG_IO (object);
+
+ switch (prop_id)
+ {
+ case PROP_INPUT:
+ g_value_set_object (value, self->priv->input);
+ break;
+ case PROP_OUTPUT:
+ g_value_set_object (value, self->priv->output);
+ break;
+ case PROP_CANCELLED:
+ g_value_set_boolean (value, self->priv->cancelled);
+ break;
+ case PROP_EXIT_STATUS:
+ g_value_set_int (value, self->priv->exit_status);
+ break;
+ case PROP_RUNNING:
+ g_value_set_boolean (value, self->priv->running);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gitg_io_cancel_impl (GitgIO *io)
+{
+ io->priv->cancelled = TRUE;
+}
+
+static void
+gitg_io_begin_impl (GitgIO *io)
+{
+ gitg_io_set_running (io, TRUE);
+}
+
+static void
+gitg_io_end_impl (GitgIO *io,
+ GError *error)
+{
+ gitg_io_set_running (io, FALSE);
+}
+
+static void
+gitg_io_class_init (GitgIOClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = gitg_io_finalize;
+ object_class->dispose = gitg_io_dispose;
+
+ object_class->get_property = gitg_io_get_property;
+ object_class->set_property = gitg_io_set_property;
+
+ klass->cancel = gitg_io_cancel_impl;
+ klass->begin = gitg_io_begin_impl;
+ klass->end = gitg_io_end_impl;
+
+ g_object_class_install_property (object_class,
+ PROP_INPUT,
+ g_param_spec_object ("input",
+ "Input",
+ "Input",
+ G_TYPE_INPUT_STREAM,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property (object_class,
+ PROP_OUTPUT,
+ g_param_spec_object ("output",
+ "Output",
+ "Output",
+ G_TYPE_OUTPUT_STREAM,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property (object_class,
+ PROP_CANCELLED,
+ g_param_spec_boolean ("cancelled",
+ "Cancelled",
+ "Cancelled",
+ FALSE,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+
+ g_object_class_install_property (object_class,
+ PROP_EXIT_STATUS,
+ g_param_spec_int ("exit-status",
+ "Exit status",
+ "Exit Status",
+ G_MININT,
+ G_MAXINT,
+ 0,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property (object_class,
+ PROP_RUNNING,
+ g_param_spec_boolean ("running",
+ "Running",
+ "Running",
+ FALSE,
+ G_PARAM_READWRITE));
+
+ signals[BEGIN] =
+ g_signal_new ("begin",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (GitgIOClass, begin),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE,
+ 0);
+
+ signals[END] =
+ g_signal_new ("end",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (GitgIOClass, end),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__BOXED,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_ERROR);
+
+ g_type_class_add_private (object_class, sizeof (GitgIOPrivate));
+}
+
+static void
+gitg_io_init (GitgIO *self)
+{
+ self->priv = GITG_IO_GET_PRIVATE (self);
+}
+
+GitgIO *
+gitg_io_new ()
+{
+ return g_object_new (GITG_TYPE_IO, NULL);
+}
+
+void
+gitg_io_begin (GitgIO *io)
+{
+ g_return_if_fail (GITG_IS_IO (io));
+
+ if (!io->priv->running)
+ {
+ g_signal_emit (io, signals[BEGIN], 0);
+ }
+}
+
+void
+gitg_io_end (GitgIO *io,
+ GError *error)
+{
+ g_return_if_fail (GITG_IS_IO (io));
+
+ if (io->priv->running)
+ {
+ g_signal_emit (io, signals[END], 0, error);
+ }
+}
+
+void
+gitg_io_cancel (GitgIO *io)
+{
+ if (GITG_IO_GET_CLASS (io)->cancel)
+ {
+ GITG_IO_GET_CLASS (io)->cancel (io);
+ }
+}
+
+gboolean
+gitg_io_get_cancelled (GitgIO *io)
+{
+ g_return_val_if_fail (GITG_IS_IO (io), FALSE);
+
+ return io->priv->cancelled;
+}
+
+void
+gitg_io_set_cancelled (GitgIO *io,
+ gboolean cancelled)
+{
+ g_return_if_fail (GITG_IS_IO (io));
+
+ if (io->priv->cancelled != cancelled)
+ {
+ io->priv->cancelled = cancelled;
+ g_object_notify (G_OBJECT (io), "cancelled");
+ }
+}
+
+void
+gitg_io_set_output (GitgIO *io,
+ GOutputStream *stream)
+{
+ g_return_if_fail (GITG_IS_IO (io));
+ g_return_if_fail (G_IS_OUTPUT_STREAM (stream));
+
+ if (io->priv->output)
+ {
+ g_object_unref (io->priv->output);
+ io->priv->output = NULL;
+ }
+
+ if (stream)
+ {
+ io->priv->output = g_object_ref (stream);
+ }
+}
+
+void
+gitg_io_set_input (GitgIO *io,
+ GInputStream *stream)
+{
+ g_return_if_fail (GITG_IS_IO (io));
+ g_return_if_fail (G_IS_INPUT_STREAM (stream));
+
+ if (io->priv->input)
+ {
+ g_object_unref (io->priv->input);
+ io->priv->input = NULL;
+ }
+
+ if (stream)
+ {
+ io->priv->input = g_object_ref (stream);
+ }
+}
+
+GInputStream *
+gitg_io_get_input (GitgIO *io)
+{
+ g_return_val_if_fail (GITG_IS_IO (io), NULL);
+ return io->priv->input;
+}
+
+GOutputStream *
+gitg_io_get_output (GitgIO *io)
+{
+ g_return_val_if_fail (GITG_IS_IO (io), NULL);
+ return io->priv->output;
+}
+
+void
+gitg_io_close (GitgIO *io)
+{
+ g_return_if_fail (GITG_IS_IO (io));
+
+ if (io->priv->input)
+ {
+ g_input_stream_close (io->priv->input, NULL, NULL);
+
+ g_object_unref (io->priv->input);
+ io->priv->input = NULL;
+ }
+
+ if (io->priv->output)
+ {
+ g_output_stream_close (io->priv->output, NULL, NULL);
+
+ g_object_unref (io->priv->output);
+ io->priv->output = NULL;
+ }
+}
+
+gint
+gitg_io_get_exit_status (GitgIO *io)
+{
+ g_return_val_if_fail (GITG_IS_IO (io), 0);
+
+ return io->priv->exit_status;
+}
+
+void
+gitg_io_set_exit_status (GitgIO *io,
+ gint exit_status)
+{
+ g_return_if_fail (GITG_IS_IO (io));
+
+ if (io->priv->exit_status != exit_status)
+ {
+ io->priv->exit_status = exit_status;
+ g_object_notify (G_OBJECT (io), "exit-status");
+ }
+}
+
+gboolean
+gitg_io_get_running (GitgIO *io)
+{
+ g_return_val_if_fail (GITG_IS_IO (io), FALSE);
+
+ return io->priv->running;
+}
+
+void
+gitg_io_set_running (GitgIO *io,
+ gboolean running)
+{
+ g_return_if_fail (GITG_IS_IO (io));
+
+ if (io->priv->running != running)
+ {
+ io->priv->running = running;
+
+ if (running)
+ {
+ io->priv->cancelled = FALSE;
+ }
+
+ g_object_notify (G_OBJECT (io), "running");
+ }
+}
diff --git a/libgitg/gitg-io.h b/libgitg/gitg-io.h
new file mode 100644
index 0000000..f240d16
--- /dev/null
+++ b/libgitg/gitg-io.h
@@ -0,0 +1,70 @@
+#ifndef __GITG_IO_H__
+#define __GITG_IO_H__
+
+#include <glib-object.h>
+#include <gio/gio.h>
+
+G_BEGIN_DECLS
+
+#define GITG_TYPE_IO (gitg_io_get_type ())
+#define GITG_IO(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GITG_TYPE_IO, GitgIO))
+#define GITG_IO_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GITG_TYPE_IO, GitgIO const))
+#define GITG_IO_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GITG_TYPE_IO, GitgIOClass))
+#define GITG_IS_IO(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GITG_TYPE_IO))
+#define GITG_IS_IO_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GITG_TYPE_IO))
+#define GITG_IO_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GITG_TYPE_IO, GitgIOClass))
+
+typedef struct _GitgIO GitgIO;
+typedef struct _GitgIOClass GitgIOClass;
+typedef struct _GitgIOPrivate GitgIOPrivate;
+
+struct _GitgIO
+{
+ /*< private >*/
+ GObject parent;
+
+ GitgIOPrivate *priv;
+
+ /*< public >*/
+};
+
+struct _GitgIOClass
+{
+ /*< private >*/
+ GObjectClass parent_class;
+
+ /*< public >*/
+ void (*cancel) (GitgIO *io);
+
+ /* Signals */
+ void (*begin) (GitgIO *io);
+ void (*end) (GitgIO *io, GError *error);
+};
+
+GType gitg_io_get_type (void) G_GNUC_CONST;
+GitgIO *gitg_io_new (void);
+
+void gitg_io_begin (GitgIO *io);
+void gitg_io_end (GitgIO *io, GError *error);
+
+void gitg_io_set_input (GitgIO *io, GInputStream *stream);
+void gitg_io_set_output (GitgIO *io, GOutputStream *stream);
+
+GInputStream *gitg_io_get_input (GitgIO *io);
+GOutputStream *gitg_io_get_output (GitgIO *io);
+
+void gitg_io_close (GitgIO *io);
+void gitg_io_cancel (GitgIO *io);
+
+gboolean gitg_io_get_cancelled (GitgIO *io);
+void gitg_io_set_cancelled (GitgIO *io, gboolean cancelled);
+
+gint gitg_io_get_exit_status (GitgIO *io);
+void gitg_io_set_exit_status (GitgIO *io, gint status);
+
+gboolean gitg_io_get_running (GitgIO *io);
+void gitg_io_set_running (GitgIO *io, gboolean running);
+
+G_END_DECLS
+
+#endif /* __GITG_IO_H__ */
diff --git a/libgitg/gitg-line-parser.c b/libgitg/gitg-line-parser.c
new file mode 100644
index 0000000..1efe4ca
--- /dev/null
+++ b/libgitg/gitg-line-parser.c
@@ -0,0 +1,452 @@
+#include "gitg-line-parser.h"
+
+
+#define GITG_LINE_PARSER_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE((object), GITG_TYPE_LINE_PARSER, GitgLineParserPrivate))
+
+struct _GitgLineParserPrivate
+{
+ gchar *rest_buffer;
+ gsize rest_buffer_size;
+
+ gchar **lines;
+ guint buffer_size;
+
+ gchar *read_buffer;
+
+ gboolean preserve_line_endings;
+};
+
+enum
+{
+ LINES,
+ DONE,
+ NUM_SIGNALS
+};
+
+G_DEFINE_TYPE (GitgLineParser, gitg_line_parser, G_TYPE_OBJECT)
+
+enum
+{
+ PROP_0,
+ PROP_BUFFER_SIZE,
+ PROP_PRESERVE_LINE_ENDINGS
+};
+
+static guint signals[NUM_SIGNALS] = {0,};
+
+typedef struct
+{
+ GitgLineParser *parser;
+ GInputStream *stream;
+ GCancellable *cancellable;
+} AsyncData;
+
+static AsyncData *
+async_data_new (GitgLineParser *parser,
+ GInputStream *stream,
+ GCancellable *cancellable)
+{
+ AsyncData *data;
+
+ data = g_slice_new (AsyncData);
+ data->parser = parser;
+ data->stream = stream;
+ data->cancellable = g_object_ref (cancellable);
+
+ return data;
+}
+
+static void
+async_data_free (AsyncData *data)
+{
+ g_object_unref (data->cancellable);
+ g_slice_free (AsyncData, data);
+}
+
+static void
+free_lines (GitgLineParser *stream)
+{
+ gint i = 0;
+
+ while (stream->priv->lines[i])
+ {
+ g_free (stream->priv->lines[i++]);
+ }
+
+ stream->priv->lines[0] = NULL;
+}
+
+static void
+gitg_line_parser_finalize (GObject *object)
+{
+ GitgLineParser *stream;
+
+ stream = GITG_LINE_PARSER (object);
+
+ free_lines (stream);
+
+ g_slice_free1 (sizeof (gchar *) * (stream->priv->buffer_size + 1), stream->priv->lines);
+ g_slice_free1 (sizeof (gchar) * (stream->priv->buffer_size + 1), stream->priv->read_buffer);
+
+ G_OBJECT_CLASS (gitg_line_parser_parent_class)->finalize (object);
+}
+
+static const gchar *
+find_newline (const gchar *ptr,
+ const gchar *end,
+ const gchar **line_end)
+{
+
+ while (ptr < end)
+ {
+ gunichar c;
+
+ c = g_utf8_get_char (ptr);
+
+ if (c == '\n')
+ {
+ /* That's it */
+ *line_end = g_utf8_next_char (ptr);
+ return ptr;
+ }
+ else if (c == '\r')
+ {
+ gchar *next;
+
+ next = g_utf8_next_char (ptr);
+
+ if (next < end)
+ {
+ gunichar n = g_utf8_get_char (next);
+
+ if (n == '\n')
+ {
+ /* Consume both! */
+ *line_end = g_utf8_next_char (next);
+ return ptr;
+ }
+ else
+ {
+ /* That's it! */
+ *line_end = next;
+ return ptr;
+ }
+ }
+ else
+ {
+ /* Need to save it, it might come later... */
+ break;
+ }
+ }
+
+ ptr = g_utf8_next_char (ptr);
+ }
+
+ return NULL;
+}
+
+static void
+parse_lines (GitgLineParser *stream,
+ const gchar *buffer,
+ gssize size)
+{
+ gchar const *ptr;
+ gchar const *newline = NULL;
+ gint i = 0;
+ gchar *all = NULL;
+ gchar const *end;
+
+ if (stream->priv->rest_buffer_size > 0)
+ {
+ GString *str = g_string_sized_new (stream->priv->rest_buffer_size + size);
+
+ g_string_append_len (str, stream->priv->rest_buffer, stream->priv->rest_buffer_size);
+ g_string_append_len (str, buffer, size);
+
+ all = g_string_free (str, FALSE);
+ size += stream->priv->rest_buffer_size;
+
+ g_free (stream->priv->rest_buffer);
+ stream->priv->rest_buffer = NULL;
+ stream->priv->rest_buffer_size = 0;
+
+ ptr = all;
+ }
+ else
+ {
+ ptr = buffer;
+ }
+
+ const gchar *line_end;
+ end = ptr + size;
+
+ while ((newline = find_newline (ptr, end, &line_end)))
+ {
+ if (stream->priv->preserve_line_endings)
+ {
+ stream->priv->lines[i++] = g_strndup (ptr, line_end - ptr);
+ }
+ else
+ {
+ stream->priv->lines[i++] = g_strndup (ptr, newline - ptr);
+ }
+
+ ptr = line_end;
+
+ if (i == stream->priv->buffer_size)
+ {
+ break;
+ }
+ }
+
+ if (ptr < end)
+ {
+ stream->priv->rest_buffer_size = end - ptr;
+ stream->priv->rest_buffer = g_strndup (ptr, stream->priv->rest_buffer_size);
+ }
+
+ stream->priv->lines[i] = NULL;
+
+ g_signal_emit (stream, signals[LINES], 0, stream->priv->lines);
+
+ g_free (all);
+}
+
+static void
+emit_rest (GitgLineParser *stream)
+{
+ if (stream->priv->rest_buffer_size > 0)
+ {
+ if (!stream->priv->preserve_line_endings &&
+ stream->priv->rest_buffer[stream->priv->rest_buffer_size - 1] == '\r')
+ {
+ stream->priv->rest_buffer[stream->priv->rest_buffer_size - 1] = '\0';
+ }
+
+ gchar *b[] = {stream->priv->rest_buffer, NULL};
+
+ g_signal_emit (stream, signals[LINES], 0, b);
+
+ g_free (stream->priv->rest_buffer);
+ stream->priv->rest_buffer = NULL;
+ stream->priv->rest_buffer_size = 0;
+ }
+}
+
+static void
+parser_done (AsyncData *data,
+ GError *error)
+{
+ if (!error)
+ {
+ emit_rest (data->parser);
+ }
+
+ g_signal_emit (data->parser, signals[DONE], 0, error);
+
+ async_data_free (data);
+}
+
+static void
+gitg_line_parser_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GitgLineParser *self = GITG_LINE_PARSER (object);
+
+ switch (prop_id)
+ {
+ case PROP_BUFFER_SIZE:
+ self->priv->buffer_size = g_value_get_uint (value);
+ break;
+ case PROP_PRESERVE_LINE_ENDINGS:
+ self->priv->preserve_line_endings = g_value_get_boolean (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gitg_line_parser_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GitgLineParser *self = GITG_LINE_PARSER (object);
+
+ switch (prop_id)
+ {
+ case PROP_BUFFER_SIZE:
+ g_value_set_uint (value, self->priv->buffer_size);
+ break;
+ case PROP_PRESERVE_LINE_ENDINGS:
+ g_value_set_boolean (value, self->priv->preserve_line_endings);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gitg_line_parser_constructed (GObject *object)
+{
+ GitgLineParser *stream;
+
+ stream = GITG_LINE_PARSER (object);
+
+ stream->priv->lines = g_slice_alloc (sizeof (gchar *) * (stream->priv->buffer_size + 1));
+ stream->priv->lines[0] = NULL;
+
+ stream->priv->read_buffer = g_slice_alloc (sizeof (gchar) * (stream->priv->buffer_size + 1));
+}
+
+static void start_read_lines (AsyncData *data);
+
+static void
+read_ready (GInputStream *stream,
+ GAsyncResult *result,
+ AsyncData *data)
+{
+ gssize read;
+ GError *error = NULL;
+
+ read = g_input_stream_read_finish (stream, result, &error);
+
+ if (g_cancellable_is_cancelled (data->cancellable))
+ {
+ if (error)
+ {
+ g_error_free (error);
+ }
+
+ async_data_free (data);
+ return;
+ }
+
+ if (read == -1)
+ {
+ parser_done (data, error);
+
+ if (error)
+ {
+ g_error_free (error);
+ }
+ }
+ else if (read == 0)
+ {
+ parser_done (data, NULL);
+ }
+ else
+ {
+ data->parser->priv->read_buffer[read] = '\0';
+
+ parse_lines (data->parser,
+ data->parser->priv->read_buffer,
+ read);
+
+ start_read_lines (data);
+ }
+}
+
+static void
+start_read_lines (AsyncData *data)
+{
+ g_input_stream_read_async (data->stream,
+ data->parser->priv->read_buffer,
+ data->parser->priv->buffer_size,
+ G_PRIORITY_DEFAULT,
+ data->cancellable,
+ (GAsyncReadyCallback)read_ready,
+ data);
+}
+
+static void
+gitg_line_parser_class_init (GitgLineParserClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = gitg_line_parser_finalize;
+ object_class->constructed = gitg_line_parser_constructed;
+
+ object_class->get_property = gitg_line_parser_get_property;
+ object_class->set_property = gitg_line_parser_set_property;
+
+ g_type_class_add_private (object_class, sizeof(GitgLineParserPrivate));
+
+ signals[LINES] =
+ g_signal_new ("lines",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__POINTER,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_POINTER);
+
+ signals[DONE] =
+ g_signal_new ("done",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__BOXED,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_ERROR);
+
+ g_object_class_install_property (object_class,
+ PROP_BUFFER_SIZE,
+ g_param_spec_uint ("buffer-size",
+ "Buffer size",
+ "Buffer Size",
+ 1,
+ G_MAXUINT,
+ 100,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+
+ g_object_class_install_property (object_class,
+ PROP_PRESERVE_LINE_ENDINGS,
+ g_param_spec_boolean ("preserve-line-endings",
+ "Preserve line endings",
+ "Preserve Line Endings",
+ FALSE,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+}
+
+static void
+gitg_line_parser_init (GitgLineParser *self)
+{
+ self->priv = GITG_LINE_PARSER_GET_PRIVATE (self);
+}
+
+GitgLineParser *
+gitg_line_parser_new (guint buffer_size,
+ gboolean preserve_line_endings)
+{
+ return g_object_new (GITG_TYPE_LINE_PARSER,
+ "buffer-size", buffer_size,
+ "preserve-line-endings", preserve_line_endings,
+ NULL);
+}
+
+void
+gitg_line_parser_parse (GitgLineParser *parser,
+ GInputStream *stream,
+ GCancellable *cancellable)
+{
+ AsyncData *data;
+
+ g_return_if_fail (GITG_IS_LINE_PARSER (parser));
+ g_return_if_fail (G_IS_INPUT_STREAM (stream));
+ g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
+
+ data = async_data_new (parser, stream, cancellable);
+ start_read_lines (data);
+}
diff --git a/libgitg/gitg-line-parser.h b/libgitg/gitg-line-parser.h
new file mode 100644
index 0000000..5f82317
--- /dev/null
+++ b/libgitg/gitg-line-parser.h
@@ -0,0 +1,45 @@
+#ifndef __GITG_LINE_PARSER_H__
+#define __GITG_LINE_PARSER_H__
+
+#include <gio/gio.h>
+
+G_BEGIN_DECLS
+
+#define GITG_TYPE_LINE_PARSER (gitg_line_parser_get_type ())
+#define GITG_LINE_PARSER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GITG_TYPE_LINE_PARSER, GitgLineParser))
+#define GITG_LINE_PARSER_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GITG_TYPE_LINE_PARSER, GitgLineParser const))
+#define GITG_LINE_PARSER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GITG_TYPE_LINE_PARSER, GitgLineParserClass))
+#define GITG_IS_LINE_PARSER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GITG_TYPE_LINE_PARSER))
+#define GITG_IS_LINE_PARSER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GITG_TYPE_LINE_PARSER))
+#define GITG_LINE_PARSER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GITG_TYPE_LINE_PARSER, GitgLineParserClass))
+
+typedef struct _GitgLineParser GitgLineParser;
+typedef struct _GitgLineParserClass GitgLineParserClass;
+typedef struct _GitgLineParserPrivate GitgLineParserPrivate;
+
+struct _GitgLineParser
+{
+ /*< private >*/
+ GObject parent;
+
+ GitgLineParserPrivate *priv;
+};
+
+struct _GitgLineParserClass
+{
+ /*< private >*/
+ GObjectClass parent_class;
+};
+
+GType gitg_line_parser_get_type (void) G_GNUC_CONST;
+
+GitgLineParser *gitg_line_parser_new (guint buffer_size,
+ gboolean preserve_line_endings);
+
+void gitg_line_parser_parse (GitgLineParser *parser,
+ GInputStream *stream,
+ GCancellable *cancellable);
+
+G_END_DECLS
+
+#endif /* __GITG_LINE_PARSER_H__ */
diff --git a/libgitg/gitg-repository.c b/libgitg/gitg-repository.c
index 3d4b1cd..303750a 100644
--- a/libgitg/gitg-repository.c
+++ b/libgitg/gitg-repository.c
@@ -26,6 +26,7 @@
#include "gitg-lanes.h"
#include "gitg-ref.h"
#include "gitg-config.h"
+#include "gitg-shell.h"
#include <gio/gio.h>
#include <sys/time.h>
@@ -91,7 +92,7 @@ struct _GitgRepositoryPrivate
GFile *git_dir;
GFile *work_tree;
- GitgRunner *loader;
+ GitgShell *loader;
GHashTable *hashtable;
gint stamp;
GType column_types[N_COLUMNS];
@@ -416,7 +417,7 @@ gitg_repository_finalize (GObject *object)
GitgRepository *rp = GITG_REPOSITORY (object);
/* Make sure to cancel the loader */
- gitg_runner_cancel (rp->priv->loader);
+ gitg_io_cancel (GITG_IO (rp->priv->loader));
g_object_unref (rp->priv->loader);
g_object_unref (rp->priv->lanes);
@@ -610,16 +611,19 @@ parse_ref_intern (GitgRepository *repository,
gchar const *ref,
gboolean symbolic)
{
- gchar **ret = gitg_repository_command_with_outputv (repository,
- NULL,
- "rev-parse",
- "--verify",
- symbolic ? "--symbolic-full-name" : ref,
- symbolic ? ref : NULL,
- NULL);
+ gchar **ret = gitg_shell_run_sync_with_output (gitg_command_newv (repository,
+ "rev-parse",
+ "--verify",
+ symbolic ? "--symbolic-full-name" : ref,
+ symbolic ? ref : NULL,
+ NULL),
+ FALSE,
+ NULL);
if (!ret)
+ {
return NULL;
+ }
gchar *r = g_strdup (*ret);
g_strfreev (ret);
@@ -748,7 +752,7 @@ gitg_repository_class_init (GitgRepositoryClass *klass)
g_param_spec_object ("loader",
"LOADER",
"The repository loader",
- GITG_TYPE_RUNNER,
+ GITG_TYPE_SHELL,
G_PARAM_READABLE));
g_object_class_install_property (object_class,
@@ -902,11 +906,11 @@ add_dummy_commit (GitgRepository *repository,
}
static void
-on_loader_end_loading (GitgRunner *object,
- gboolean cancelled,
+on_loader_end_loading (GitgShell *object,
+ GError *error,
GitgRepository *repository)
{
- if (cancelled)
+ if (gitg_io_get_cancelled (GITG_IO (object)))
{
g_signal_emit (repository, repository_signals[LOADED], 0);
return;
@@ -931,7 +935,7 @@ on_loader_end_loading (GitgRunner *object,
if (current == LOAD_STAGE_STAGED)
{
/* Check if there are unstaged changes */
- if (show_staged && gitg_runner_get_exit_status (object) != 0)
+ if (show_staged && gitg_io_get_exit_status (GITG_IO (object)) != 0)
{
add_dummy_commit (repository, TRUE);
}
@@ -941,28 +945,29 @@ on_loader_end_loading (GitgRunner *object,
cached = "--cached";
}
- gitg_repository_run_commandv (repository,
- object,
- NULL,
- "diff-index",
- "--quiet",
- head,
- cached,
- NULL);
+ gitg_shell_run (object,
+ gitg_command_newv (repository,
+ "diff-index",
+ "--no-ext-diff",
+ "--quiet",
+ head,
+ cached,
+ NULL),
+ NULL);
+
g_free (head);
}
break;
case LOAD_STAGE_UNSTAGED:
- if (show_unstaged && gitg_runner_get_exit_status (object) != 0)
+ if (show_unstaged && gitg_io_get_exit_status (GITG_IO (object)) != 0)
{
add_dummy_commit (repository, FALSE);
}
- gitg_repository_run_command (repository,
- object,
- (gchar const **)repository->priv->last_args,
- NULL);
-
+ gitg_shell_run (object,
+ gitg_command_new (repository,
+ (gchar const * const *)repository->priv->last_args),
+ NULL);
break;
default:
break;
@@ -1106,7 +1111,7 @@ loader_update_commits (GitgRepository *self,
}
static void
-on_loader_update (GitgRunner *object,
+on_loader_update (GitgShell *object,
gchar **buffer,
GitgRepository *repository)
{
@@ -1294,7 +1299,7 @@ gitg_repository_init (GitgRepository *object)
NULL,
(GDestroyNotify)free_refs);
- object->priv->loader = gitg_runner_new (10000);
+ object->priv->loader = gitg_shell_new (10000);
g_signal_connect (object->priv->loader,
"update",
@@ -1302,7 +1307,7 @@ gitg_repository_init (GitgRepository *object)
object);
g_signal_connect (object->priv->loader,
- "end-loading",
+ "end",
G_CALLBACK (on_loader_end_loading),
object);
}
@@ -1361,11 +1366,11 @@ gitg_repository_get_git_dir (GitgRepository *self)
return g_file_dup (self->priv->git_dir);
}
-GitgRunner *
+GitgShell *
gitg_repository_get_loader (GitgRepository *self)
{
g_return_val_if_fail (GITG_IS_REPOSITORY (self), NULL);
- return GITG_RUNNER (g_object_ref (self->priv->loader));
+ return GITG_SHELL (g_object_ref (self->priv->loader));
}
static gboolean
@@ -1382,15 +1387,15 @@ reload_revisions (GitgRepository *repository,
repository->priv->load_stage = LOAD_STAGE_STASH;
- return gitg_repository_run_commandv (repository,
- repository->priv->loader,
- error,
- "log",
- "--pretty=format:%H\x01%an\x01%ae\x01%at\x01%s",
- "--encoding=UTF-8",
- "-g",
- "refs/stash",
- NULL);
+ return gitg_shell_run (repository->priv->loader,
+ gitg_command_newv (repository,
+ "log",
+ "--pretty=format:%H\x01%an\x01%ae\x01%at\x01%s",
+ "--encoding=UTF-8",
+ "-g",
+ "refs/stash",
+ NULL),
+ error);
}
static gchar *
@@ -1402,7 +1407,9 @@ load_current_ref (GitgRepository *self)
gint numargs;
if (self->priv->last_args == NULL)
+ {
return NULL;
+ }
numargs = g_strv_length (self->priv->last_args);
@@ -1417,14 +1424,16 @@ load_current_ref (GitgRepository *self)
argv[2 + i] = self->priv->last_args[i];
}
- out = gitg_repository_command_with_output (self, argv, NULL);
+ out = gitg_shell_run_sync_with_output (gitg_command_new (self, argv),
+ FALSE,
+ NULL);
if (!out)
{
return NULL;
}
- if (*out && !* (out + 1))
+ if (*out && !*(out + 1))
{
ret = g_strdup (*out);
}
@@ -1438,12 +1447,13 @@ load_refs (GitgRepository *self)
{
gchar **refs;
- refs = gitg_repository_command_with_outputv (self,
- NULL,
- "for-each-ref",
- "--format=%(refname) %(objectname) %(*objectname)",
- "refs",
- NULL);
+ refs = gitg_shell_run_sync_with_output (gitg_command_newv (self,
+ "for-each-ref",
+ "--format=%(refname) %(objectname) %(*objectname)",
+ "refs",
+ NULL),
+ FALSE,
+ NULL);
if (!refs)
{
@@ -1491,7 +1501,7 @@ gitg_repository_reload (GitgRepository *repository)
g_return_if_fail (GITG_IS_REPOSITORY (repository));
g_return_if_fail (repository->priv->git_dir != NULL);
- gitg_runner_cancel (repository->priv->loader);
+ gitg_io_cancel (GITG_IO (repository->priv->loader));
repository->priv->load_stage = LOAD_STAGE_NONE;
gitg_repository_clear (repository);
@@ -1520,7 +1530,7 @@ gitg_repository_load (GitgRepository *self,
return FALSE;
}
- gitg_runner_cancel (self->priv->loader);
+ gitg_io_cancel (GITG_IO (self->priv->loader));
gitg_repository_clear (self);
build_log_args (self, argc, av);
@@ -1622,6 +1632,24 @@ gitg_repository_find (GitgRepository *store,
iter);
}
+static gint
+ref_compare (GitgRef *a,
+ GitgRef *b)
+{
+ GitgRefType t1 = gitg_ref_get_ref_type (a);
+ GitgRefType t2 = gitg_ref_get_ref_type (b);
+
+ if (t1 != t2)
+ {
+ return t1 < t2 ? -1 : 1;
+ }
+ else
+ {
+ return g_strcmp0 (gitg_ref_get_shortname (a),
+ gitg_ref_get_shortname (b));
+ }
+}
+
GSList *
gitg_repository_get_refs (GitgRepository *repository)
{
@@ -1635,13 +1663,14 @@ gitg_repository_get_refs (GitgRepository *repository)
{
GSList *val;
- for (val = (GSList *)item->data; val; val = val->next)
+ for (val = item->data; val; val = val->next)
{
- ret = g_slist_prepend (ret, gitg_ref_copy ( (GitgRef *)val->data));
+ ret = g_slist_insert_sorted (ret,
+ gitg_ref_copy (val->data),
+ (GCompareFunc)ref_compare);
}
}
- ret = g_slist_reverse (ret);
g_list_free (values);
return ret;
@@ -1673,297 +1702,6 @@ gitg_repository_relative (GitgRepository *repository,
return g_file_get_relative_path (repository->priv->work_tree, file);
}
-gboolean
-gitg_repository_run_command_with_input (GitgRepository *repository,
- GitgRunner *runner,
- gchar const **argv,
- gchar const *input,
- GError **error)
-{
- g_return_val_if_fail (GITG_IS_REPOSITORY (repository), FALSE);
- g_return_val_if_fail (GITG_IS_RUNNER (runner), FALSE);
- g_return_val_if_fail (repository->priv->git_dir != NULL, FALSE);
-
- guint num = g_strv_length ( (gchar **)argv);
- guint i;
-
- gchar const **args = g_new0 (gchar const *, num + 6);
-
- gchar *git_dir_path = g_file_get_path (repository->priv->git_dir);
- gchar *work_tree_path = g_file_get_path (repository->priv->work_tree);
-
- args[0] = "git";
- args[1] = "--git-dir";
- args[2] = git_dir_path;
- args[3] = "--work-tree";
- args[4] = work_tree_path;
-
- for (i = 0; i < num; ++i)
- {
- args[i + 5] = argv[i];
- }
-
- gboolean ret = gitg_runner_run_with_arguments (runner,
- repository->priv->work_tree,
- args,
- input,
- error);
-
- g_free (args);
- g_free (git_dir_path);
- g_free (work_tree_path);
-
- return ret;
-}
-
-gboolean
-gitg_repository_run_command (GitgRepository *repository,
- GitgRunner *runner,
- gchar const **argv,
- GError **error)
-{
- g_return_val_if_fail (GITG_IS_REPOSITORY (repository), FALSE);
- g_return_val_if_fail (GITG_IS_RUNNER (runner), FALSE);
- g_return_val_if_fail (repository->priv->git_dir != NULL, FALSE);
-
- return gitg_repository_run_command_with_input (repository,
- runner,
- argv,
- NULL,
- error);
-}
-
-gboolean
-gitg_repository_command_with_input (GitgRepository *repository,
- gchar const **argv,
- gchar const *input,
- GError **error)
-{
- g_return_val_if_fail (GITG_IS_REPOSITORY (repository), FALSE);
- g_return_val_if_fail (repository->priv->git_dir != NULL, FALSE);
-
- GitgRunner *runner = gitg_runner_new_synchronized (1000);
-
- gboolean ret = gitg_repository_run_command_with_input (repository,
- runner,
- argv,
- input,
- error);
- g_object_unref (runner);
-
- return ret;
-}
-
-gboolean
-gitg_repository_command (GitgRepository *repository,
- gchar const **argv,
- GError **error)
-{
- g_return_val_if_fail (GITG_IS_REPOSITORY (repository), FALSE);
- g_return_val_if_fail (repository->priv->git_dir != NULL, FALSE);
-
- return gitg_repository_command_with_input (repository,
- argv,
- NULL,
- error);
-}
-
-typedef struct
-{
- gchar **buffer;
- guint size;
-} CommandOutput;
-
-static void
-command_with_output_update (GitgRunner *runner,
- gchar **buffer,
- CommandOutput *output)
-{
- guint num = g_strv_length (buffer);
- guint i;
-
- output->buffer = g_realloc (output->buffer,
- sizeof (gchar *) * (output->size + num + 1));
-
- for (i = 0; i < num; ++i)
- {
- output->buffer[output->size + i] = g_strdup (buffer[i]);
- }
-
- output->size += num;
- output->buffer[output->size] = NULL;
-}
-
-gchar **
-gitg_repository_command_with_input_and_output (GitgRepository *repository,
- gchar const **argv,
- gchar const *input,
- GError **error)
-{
- g_return_val_if_fail (GITG_IS_REPOSITORY (repository), NULL);
- g_return_val_if_fail (repository->priv->git_dir != NULL, NULL);
-
- GitgRunner *runner = gitg_runner_new_synchronized (1000);
- CommandOutput output = {NULL, 0};
-
- g_signal_connect (runner, "update", G_CALLBACK (command_with_output_update), &output);
- gboolean ret = gitg_repository_run_command_with_input (repository,
- runner,
- argv,
- input,
- error);
-
- if (!ret)
- {
- g_strfreev (output.buffer);
- output.buffer = NULL;
- }
-
- g_object_unref (runner);
- return output.buffer;
-}
-
-gchar **
-gitg_repository_command_with_output (GitgRepository *repository,
- gchar const **argv,
- GError **error)
-{
- g_return_val_if_fail (GITG_IS_REPOSITORY (repository), NULL);
- g_return_val_if_fail (repository->priv->git_dir != NULL, NULL);
-
- return gitg_repository_command_with_input_and_output (repository,
- argv,
- NULL,
- error);
-}
-
-static gchar const **
-parse_valist (va_list ap)
-{
- gchar const *a;
- gchar const **ret = NULL;
- guint num = 0;
-
- while ( (a = va_arg (ap, gchar const *)) != NULL)
- {
- ret = g_realloc (ret, sizeof (gchar const *) * (++num + 1));
- ret[num - 1] = a;
- }
-
- ret[num] = NULL;
- return ret;
-}
-
-gboolean
-gitg_repository_commandv (GitgRepository *repository,
- GError **error,
- ...)
-{
- va_list ap;
- va_start (ap, error);
- gchar const **argv = parse_valist (ap);
- va_end (ap);
-
- gboolean ret = gitg_repository_command (repository, argv, error);
- g_free (argv);
- return ret;
-}
-
-gboolean
-gitg_repository_command_with_inputv (GitgRepository *repository,
- gchar const *input,
- GError **error,
- ...)
-{
- va_list ap;
- va_start (ap, error);
- gchar const **argv = parse_valist (ap);
- va_end (ap);
-
- gboolean ret = gitg_repository_command_with_input (repository,
- argv,
- input,
- error);
- g_free (argv);
- return ret;
-}
-
-gboolean
-gitg_repository_run_commandv (GitgRepository *repository,
- GitgRunner *runner,
- GError **error,
- ...)
-{
- va_list ap;
- va_start (ap, error);
- gchar const **argv = parse_valist (ap);
- va_end (ap);
-
- gboolean ret = gitg_repository_run_command (repository,
- runner,
- argv,
- error);
- g_free (argv);
- return ret;
-}
-
-gboolean
-gitg_repository_run_command_with_inputv (GitgRepository *repository,
- GitgRunner *runner,
- gchar const *input,
- GError **error,
- ...)
-{
- va_list ap;
- va_start (ap, error);
- gchar const **argv = parse_valist (ap);
- va_end (ap);
-
- gboolean ret = gitg_repository_run_command_with_input (repository,
- runner,
- argv,
- input,
- error);
- g_free (argv);
- return ret;
-}
-
-gchar **
-gitg_repository_command_with_outputv (GitgRepository *repository,
- GError **error,
- ...)
-{
- va_list ap;
- va_start (ap, error);
- gchar const **argv = parse_valist (ap);
- va_end (ap);
-
- gchar **ret = gitg_repository_command_with_output (repository,
- argv,
- error);
- g_free (argv);
- return ret;
-}
-
-gchar **
-gitg_repository_command_with_input_and_outputv (GitgRepository *repository,
- gchar const *input,
- GError **error,
- ...)
-{
- va_list ap;
- va_start (ap, error);
- gchar const **argv = parse_valist (ap);
- va_end (ap);
-
- gchar **ret = gitg_repository_command_with_input_and_output (repository,
- argv,
- input,
- error);
- g_free (argv);
- return ret;
-}
-
gchar *
gitg_repository_parse_ref (GitgRepository *repository,
gchar const *ref)
@@ -2148,8 +1886,9 @@ gboolean
gitg_repository_get_loaded (GitgRepository *repository)
{
g_return_val_if_fail (GITG_IS_REPOSITORY (repository), FALSE);
+
return repository->priv->load_stage == LOAD_STAGE_LAST &&
- !gitg_runner_running (repository->priv->loader);
+ !gitg_io_get_running (GITG_IO (repository->priv->loader));
}
gchar const **
diff --git a/libgitg/gitg-repository.h b/libgitg/gitg-repository.h
index 01f4ed0..158ab23 100644
--- a/libgitg/gitg-repository.h
+++ b/libgitg/gitg-repository.h
@@ -26,7 +26,6 @@
#include <gtk/gtk.h>
#include <libgitg/gitg-revision.h>
-#include <libgitg/gitg-runner.h>
#include <libgitg/gitg-ref.h>
G_BEGIN_DECLS
@@ -43,7 +42,9 @@ typedef struct _GitgRepository GitgRepository;
typedef struct _GitgRepositoryClass GitgRepositoryClass;
typedef struct _GitgRepositoryPrivate GitgRepositoryPrivate;
-typedef enum
+struct _GitgShell;
+
+typedef enum
{
GITG_REPOSITORY_NO_ERROR = 0,
GITG_REPOSITORY_ERROR_NOT_FOUND
@@ -74,8 +75,6 @@ GFile *gitg_repository_get_git_dir (GitgRepository *repository);
gboolean gitg_repository_exists (GitgRepository *repository);
-GitgRunner *gitg_repository_get_loader(GitgRepository *repository);
-
gboolean gitg_repository_load(GitgRepository *repository, int argc, gchar const **argv, GError **error);
gboolean gitg_repository_get_loaded(GitgRepository *repository);
@@ -93,30 +92,13 @@ GitgRef *gitg_repository_get_current_working_ref(GitgRepository *repository);
gchar *gitg_repository_relative(GitgRepository *repository, GFile *file);
-/* Running git commands */
-gboolean gitg_repository_run_command(GitgRepository *repository, GitgRunner *runner, gchar const **argv, GError **error);
-gboolean gitg_repository_run_commandv(GitgRepository *repository, GitgRunner *runner, GError **error, ...) G_GNUC_NULL_TERMINATED;
-
-gboolean gitg_repository_run_command_with_input(GitgRepository *repository, GitgRunner *runner, gchar const **argv, gchar const *input, GError **error);
-gboolean gitg_repository_run_command_with_inputv(GitgRepository *repository, GitgRunner *runner, gchar const *input, GError **error, ...) G_GNUC_NULL_TERMINATED;
-
-gboolean gitg_repository_command_with_input(GitgRepository *repository, gchar const **argv, gchar const *input, GError **error);
-gboolean gitg_repository_command_with_inputv(GitgRepository *repository, gchar const *input, GError **error, ...) G_GNUC_NULL_TERMINATED;
-
-gboolean gitg_repository_command(GitgRepository *repository, gchar const **argv, GError **error);
-gboolean gitg_repository_commandv(GitgRepository *repository, GError **error, ...) G_GNUC_NULL_TERMINATED;
-
-gchar **gitg_repository_command_with_output(GitgRepository *repository, gchar const **argv, GError **error);
-gchar **gitg_repository_command_with_outputv(GitgRepository *repository, GError **error, ...) G_GNUC_NULL_TERMINATED;
-
-gchar **gitg_repository_command_with_input_and_output(GitgRepository *repository, gchar const **argv, gchar const *input, GError **error);
-gchar **gitg_repository_command_with_input_and_outputv(GitgRepository *repository, gchar const *input, GError **error, ...) G_GNUC_NULL_TERMINATED;
-
gchar *gitg_repository_parse_ref(GitgRepository *repository, gchar const *ref);
gchar *gitg_repository_parse_head(GitgRepository *repository);
void gitg_repository_reload(GitgRepository *repository);
+struct _GitgShell *gitg_repository_get_loader (GitgRepository *repository);
+
gchar **gitg_repository_get_remotes (GitgRepository *repository);
GSList const *gitg_repository_get_ref_pushes (GitgRepository *repository, GitgRef *ref);
gchar const **gitg_repository_get_current_selection (GitgRepository *repository);
diff --git a/libgitg/gitg-runner.c b/libgitg/gitg-runner.c
index 0b4371e..dc19547 100644
--- a/libgitg/gitg-runner.c
+++ b/libgitg/gitg-runner.c
@@ -1,28 +1,6 @@
-/*
- * gitg-runner.c
- * This file is part of gitg - git repository viewer
- *
- * Copyright (C) 2009 - Jesse van den Kieboom
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-#include "gitg-convert.h"
-#include "gitg-debug.h"
#include "gitg-runner.h"
+#include "gitg-debug.h"
+
#include "gitg-smart-charset-converter.h"
#include <string.h>
@@ -31,56 +9,33 @@
#include <errno.h>
#include <stdlib.h>
-#include <gio/gio.h>
#include <gio/gunixoutputstream.h>
#include <gio/gunixinputstream.h>
#define GITG_RUNNER_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE((object), GITG_TYPE_RUNNER, GitgRunnerPrivate))
-/* Signals */
-enum
-{
- BEGIN_LOADING,
- UPDATE,
- END_LOADING,
- LAST_SIGNAL
-};
-
-static guint runner_signals[LAST_SIGNAL] = { 0 };
-
-/* Properties */
-enum
+struct _GitgRunnerPrivate
{
- PROP_0,
+ GitgCommand *command;
- PROP_BUFFER_SIZE,
- PROP_SYNCHRONIZED,
- PROP_PRESERVE_LINE_ENDINGS
-};
+ GInputStream *stdout;
+ GOutputStream *stdin;
-struct _GitgRunnerPrivate
-{
- GPid pid;
- GInputStream *input_stream;
- GOutputStream *output_stream;
GCancellable *cancellable;
+ gboolean cancelled;
- guint buffer_size;
- gchar *read_buffer;
- gchar **lines;
- gchar **environment;
-
- gchar *rest_buffer;
- gssize rest_buffer_size;
+ GPid pid;
+ guint watch_id;
+};
- gint exit_status;
+G_DEFINE_TYPE (GitgRunner, gitg_runner, GITG_TYPE_IO)
- guint synchronized : 1;
- guint preserve_line_endings : 1;
+enum
+{
+ PROP_0,
+ PROP_COMMAND
};
-G_DEFINE_TYPE (GitgRunner, gitg_runner, G_TYPE_OBJECT)
-
typedef struct
{
GitgRunner *runner;
@@ -88,12 +43,14 @@ typedef struct
} AsyncData;
static AsyncData *
-async_data_new (GitgRunner *runner,
- GCancellable *cancellable)
+async_data_new (GitgRunner *runner)
{
- AsyncData *data = g_slice_new (AsyncData);
+ AsyncData *data;
+
+ data = g_slice_new (AsyncData);
+
data->runner = runner;
- data->cancellable = g_object_ref (cancellable);
+ data->cancellable = g_object_ref (runner->priv->cancellable);
return data;
}
@@ -105,587 +62,257 @@ async_data_free (AsyncData *data)
g_slice_free (AsyncData, data);
}
-GQuark
-gitg_runner_error_quark (void)
+static void
+gitg_runner_finalize (GObject *object)
{
- static GQuark quark = 0;
-
- if (G_UNLIKELY (quark == 0))
- {
- quark = g_quark_from_string ("gitg_runner_error");
- }
-
- return quark;
+ G_OBJECT_CLASS (gitg_runner_parent_class)->finalize (object);
}
static void
-runner_io_exit (GPid pid,
- gint status,
- GitgRunner *runner)
+close_streams (GitgRunner *runner)
{
- g_spawn_close_pid (pid);
-
- if (runner->priv->pid)
+ if (runner->priv->cancellable)
{
- runner->priv->pid = 0;
- runner->priv->exit_status = status;
+ g_cancellable_cancel (runner->priv->cancellable);
}
-}
-static void
-free_lines (GitgRunner *runner)
-{
- gint i = 0;
+ if (runner->priv->stdin != NULL)
+ {
+ g_output_stream_close (runner->priv->stdin, NULL, NULL);
+ g_object_unref (runner->priv->stdin);
+
+ runner->priv->stdin = NULL;
+ }
- while (runner->priv->lines[i])
+ if (runner->priv->stdout != NULL)
{
- g_free (runner->priv->lines[i++]);
+ g_input_stream_close (runner->priv->stdout, NULL, NULL);
+ g_object_unref (runner->priv->stdout);
+
+ runner->priv->stdout = NULL;
}
- runner->priv->lines[0] = NULL;
+ gitg_io_close (GITG_IO (runner));
}
static void
-gitg_runner_finalize (GObject *object)
+gitg_runner_dispose (GObject *object)
{
- GitgRunner *runner = GITG_RUNNER (object);
-
- /* Cancel possible running */
- gitg_runner_cancel (runner);
+ GitgRunner *runner;
- /* Free potential stored lines */
- free_lines (runner);
+ runner = GITG_RUNNER (object);
- /* Remove buffer slice */
- g_slice_free1 (sizeof (gchar) * (runner->priv->buffer_size + 1), runner->priv->read_buffer);
- g_slice_free1 (sizeof (gchar *) * (runner->priv->buffer_size + 1), runner->priv->lines);
+ if (runner->priv->command != NULL)
+ {
+ g_object_unref (runner->priv->command);
+ runner->priv->command = NULL;
+ }
- /* Remove line buffer */
- g_free (runner->priv->rest_buffer);
- g_strfreev (runner->priv->environment);
+ gitg_io_cancel (GITG_IO (runner));
- g_object_unref (runner->priv->cancellable);
+ close_streams (runner);
- G_OBJECT_CLASS (gitg_runner_parent_class)->finalize (object);
+ G_OBJECT_CLASS (gitg_runner_parent_class)->dispose (object);
}
static void
-gitg_runner_get_property (GObject *object,
- guint prop_id,
- GValue *value,
- GParamSpec *pspec)
+gitg_runner_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
{
- GitgRunner *runner = GITG_RUNNER (object);
+ GitgRunner *self = GITG_RUNNER (object);
switch (prop_id)
{
- case PROP_BUFFER_SIZE:
- g_value_set_uint (value, runner->priv->buffer_size);
- break;
- case PROP_SYNCHRONIZED:
- g_value_set_boolean (value, runner->priv->synchronized);
- break;
- case PROP_PRESERVE_LINE_ENDINGS:
- g_value_set_boolean (value, runner->priv->preserve_line_endings);
+ case PROP_COMMAND:
+ gitg_runner_set_command (self, g_value_get_object (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
+ break;
}
}
static void
-set_buffer_size (GitgRunner *runner,
- guint buffer_size)
-{
- runner->priv->buffer_size = buffer_size;
- runner->priv->lines = g_slice_alloc (sizeof (gchar *) * (runner->priv->buffer_size + 1));
- runner->priv->lines[0] = NULL;
-
- runner->priv->read_buffer = g_slice_alloc (sizeof (gchar) * (runner->priv->buffer_size + 1));
-}
-
-static void
-gitg_runner_set_property (GObject *object,
- guint prop_id,
- const GValue *value,
- GParamSpec *pspec)
+gitg_runner_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
{
- GitgRunner *runner = GITG_RUNNER (object);
+ GitgRunner *self = GITG_RUNNER (object);
switch (prop_id)
{
- case PROP_BUFFER_SIZE:
- set_buffer_size (runner, g_value_get_uint (value));
- break;
- case PROP_SYNCHRONIZED:
- runner->priv->synchronized = g_value_get_boolean (value);
- break;
- case PROP_PRESERVE_LINE_ENDINGS:
- runner->priv->preserve_line_endings = g_value_get_boolean (value);
+ case PROP_COMMAND:
+ g_value_set_object (value, self->priv->command);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
+ break;
}
}
static void
-gitg_runner_class_init (GitgRunnerClass *klass)
+dummy_cb (GPid pid,
+ gint status,
+ gpointer data)
{
- GObjectClass *object_class = G_OBJECT_CLASS (klass);
-
- object_class->finalize = gitg_runner_finalize;
-
- object_class->get_property = gitg_runner_get_property;
- object_class->set_property = gitg_runner_set_property;
-
- g_object_class_install_property (object_class, PROP_BUFFER_SIZE,
- g_param_spec_uint ("buffer_size",
- "BUFFER SIZE",
- "The runners buffer size",
- 1,
- G_MAXUINT,
- 1,
- G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
-
- g_object_class_install_property (object_class, PROP_SYNCHRONIZED,
- g_param_spec_boolean ("synchronized",
- "SYNCHRONIZED",
- "Whether the command is ran synchronized",
- FALSE,
- G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
-
- runner_signals[BEGIN_LOADING] =
- g_signal_new ("begin-loading",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (GitgRunnerClass,
- begin_loading),
- NULL,
- NULL,
- g_cclosure_marshal_VOID__VOID,
- G_TYPE_NONE,
- 0);
-
- runner_signals[UPDATE] =
- g_signal_new ("update",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (GitgRunnerClass,
- update),
- NULL,
- NULL,
- g_cclosure_marshal_VOID__POINTER,
- G_TYPE_NONE,
- 1,
- G_TYPE_POINTER);
-
- runner_signals[END_LOADING] =
- g_signal_new ("end-loading",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (GitgRunnerClass,
- end_loading),
- NULL,
- NULL,
- g_cclosure_marshal_VOID__BOOLEAN,
- G_TYPE_NONE,
- 1,
- G_TYPE_BOOLEAN);
-
- g_type_class_add_private (object_class, sizeof (GitgRunnerPrivate));
-
- g_object_class_install_property (object_class,
- PROP_PRESERVE_LINE_ENDINGS,
- g_param_spec_boolean ("preserve-line-endings",
- "Preserve Line Endings",
- "preserve line endings",
- FALSE,
- G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
}
static void
-gitg_runner_init (GitgRunner *self)
-{
- self->priv = GITG_RUNNER_GET_PRIVATE (self);
-
- self->priv->cancellable = g_cancellable_new ();
-}
-
-GitgRunner *
-gitg_runner_new (guint buffer_size)
-{
- g_assert (buffer_size > 0);
-
- return GITG_RUNNER (g_object_new (GITG_TYPE_RUNNER,
- "buffer_size",
- buffer_size,
- "synchronized",
- FALSE,
- NULL));
-}
-
-GitgRunner *
-gitg_runner_new_synchronized (guint buffer_size)
+kill_process (GitgRunner *runner)
{
- g_assert (buffer_size > 0);
-
- return GITG_RUNNER (g_object_new (GITG_TYPE_RUNNER,
- "buffer_size",
- buffer_size,
- "synchronized",
- TRUE,
- NULL));
-}
-
-void
-gitg_runner_set_preserve_line_endings (GitgRunner *runner,
- gboolean preserve_line_endings)
-{
- g_return_if_fail (GITG_IS_RUNNER (runner));
-
- runner->priv->preserve_line_endings = preserve_line_endings;
- g_object_notify (G_OBJECT (runner), "preserve-line-endings");
-}
-
-gboolean
-gitg_runner_get_preserve_line_endings (GitgRunner *runner)
-{
- g_return_val_if_fail (GITG_IS_RUNNER (runner), FALSE);
-
- return runner->priv->preserve_line_endings;
-}
-
-static gchar *
-find_newline (gchar *ptr,
- gchar *end,
- gchar **line_end)
-{
-
- while (ptr < end)
+ if (runner->priv->pid == 0)
{
- gunichar c;
+ return;
+ }
- c = g_utf8_get_char (ptr);
+ /* We remove our handler for the process here and install a dummy
+ handler later so it will still be properly reaped */
+ g_source_remove (runner->priv->watch_id);
+ kill (runner->priv->pid, SIGTERM);
- if (c == '\n')
- {
- /* That's it */
- *line_end = g_utf8_next_char (ptr);
- return ptr;
- }
- else if (c == '\r')
- {
- gchar *next;
-
- next = g_utf8_next_char (ptr);
-
- if (next < end)
- {
- gunichar n = g_utf8_get_char (next);
-
- if (n == '\n')
- {
- /* Consume both! */
- *line_end = g_utf8_next_char (next);
- return ptr;
- }
- else
- {
- /* That's it! */
- *line_end = next;
- return ptr;
- }
- }
- else
- {
- /* Need to save it, it might come later... */
- break;
- }
- }
+ g_child_watch_add (runner->priv->pid, dummy_cb, NULL);
- ptr = g_utf8_next_char (ptr);
- }
+ runner->priv->pid = 0;
- return NULL;
+ gitg_io_set_exit_status (GITG_IO (runner), EXIT_FAILURE);
}
static void
-parse_lines (GitgRunner *runner,
- gchar *buffer,
- gssize size)
+runner_done (GitgRunner *runner,
+ GError *error)
{
- gchar *ptr;
- gchar *newline = NULL;
- gint i = 0;
- gchar *all;
- gchar *end;
-
- free_lines (runner);
+ close_streams (runner);
+ kill_process (runner);
- if (runner->priv->rest_buffer_size > 0)
+ if (!error && gitg_io_get_exit_status (GITG_IO (runner)) != 0)
{
- GString *str = g_string_sized_new (runner->priv->rest_buffer_size + size);
-
- g_string_append_len (str, runner->priv->rest_buffer, runner->priv->rest_buffer_size);
- g_string_append_len (str, buffer, size);
+ GError *err;
- all = g_string_free (str, FALSE);
- size += runner->priv->rest_buffer_size;
+ err = g_error_new (G_IO_ERROR,
+ G_IO_ERROR_FAILED,
+ "Process exited with non-zero exit code: %d",
+ gitg_io_get_exit_status (GITG_IO (runner)));
- g_free (runner->priv->rest_buffer);
- runner->priv->rest_buffer = NULL;
- runner->priv->rest_buffer_size = 0;
+ gitg_io_end (GITG_IO (runner), err);
+ g_error_free (err);
}
else
{
- all = buffer;
+ gitg_io_end (GITG_IO (runner), error);
}
+}
- ptr = all;
+static void
+gitg_runner_cancel (GitgIO *io)
+{
+ gboolean was_running;
+ GitgRunner *runner;
- gchar *line_end;
- end = ptr + size;
+ runner = GITG_RUNNER (io);
- while ((newline = find_newline (ptr, end, &line_end)))
+ if (runner->priv->cancellable)
{
- if (runner->priv->preserve_line_endings)
- {
- runner->priv->lines[i++] = g_strndup (ptr, line_end - ptr);
- }
- else
- {
- runner->priv->lines[i++] = g_strndup (ptr, newline - ptr);
- }
-
- ptr = line_end;
- }
+ g_cancellable_cancel (runner->priv->cancellable);
- if (ptr < end)
- {
- runner->priv->rest_buffer_size = end - ptr;
- runner->priv->rest_buffer = g_strndup (ptr, runner->priv->rest_buffer_size);
+ g_object_unref (runner->priv->cancellable);
+ runner->priv->cancellable = NULL;
}
- runner->priv->lines[i] = NULL;
+ was_running = gitg_io_get_running (GITG_IO (runner));
- g_signal_emit (runner, runner_signals[UPDATE], 0, runner->priv->lines);
+ GITG_IO_CLASS (gitg_runner_parent_class)->cancel (GITG_IO (runner));
- if (all != buffer)
+ if (was_running)
{
- g_free (all);
+ runner_done (runner, NULL);
}
}
static void
-close_streams (GitgRunner *runner)
+gitg_runner_class_init (GitgRunnerClass *klass)
{
- if (runner->priv->output_stream)
- {
- g_output_stream_close (runner->priv->output_stream, NULL, NULL);
- g_object_unref (runner->priv->output_stream);
- runner->priv->output_stream = NULL;
- }
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GitgIOClass *io_class = GITG_IO_CLASS (klass);
- if (runner->priv->input_stream)
- {
- g_input_stream_close (runner->priv->input_stream, NULL, NULL);
- g_object_unref (runner->priv->input_stream);
- runner->priv->input_stream = NULL;
- }
+ object_class->finalize = gitg_runner_finalize;
+ object_class->dispose = gitg_runner_dispose;
- g_free (runner->priv->rest_buffer);
- runner->priv->rest_buffer = NULL;
- runner->priv->rest_buffer_size = 0;
-}
+ object_class->get_property = gitg_runner_get_property;
+ object_class->set_property = gitg_runner_set_property;
-static void
-emit_rest (GitgRunner *runner)
-{
- if (runner->priv->rest_buffer_size > 0)
- {
- if (!runner->priv->preserve_line_endings &&
- runner->priv->rest_buffer[runner->priv->rest_buffer_size - 1] == '\r')
- {
- runner->priv->rest_buffer[runner->priv->rest_buffer_size - 1] = '\0';
- }
+ io_class->cancel = gitg_runner_cancel;
- gchar *b[] = {runner->priv->rest_buffer, NULL};
+ g_type_class_add_private (object_class, sizeof(GitgRunnerPrivate));
- g_signal_emit (runner, runner_signals[UPDATE], 0, b);
- }
+ g_object_class_install_property (object_class,
+ PROP_COMMAND,
+ g_param_spec_object ("command",
+ "Command",
+ "Command",
+ GITG_TYPE_COMMAND,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
}
-static gboolean
-run_sync (GitgRunner *runner,
- gchar const *input,
- GError **error)
+static void
+gitg_runner_init (GitgRunner *self)
{
- if (input)
- {
- if (!g_output_stream_write_all (runner->priv->output_stream,
- input,
- strlen (input),
- NULL,
- NULL,
- error))
- {
- runner_io_exit (runner->priv->pid, 1, runner);
- close_streams (runner);
-
- g_signal_emit (runner, runner_signals[END_LOADING], 0, FALSE);
- return FALSE;
- }
-
- g_output_stream_close (runner->priv->output_stream, NULL, NULL);
- }
-
- gsize read = runner->priv->buffer_size;
-
- while (read == runner->priv->buffer_size)
- {
- if (!g_input_stream_read_all (runner->priv->input_stream,
- runner->priv->read_buffer,
- runner->priv->buffer_size,
- &read,
- NULL,
- error))
- {
- runner_io_exit (runner->priv->pid, 1, runner);
- close_streams (runner);
-
- g_signal_emit (runner, runner_signals[END_LOADING], 0, TRUE);
- return FALSE;
- }
-
- runner->priv->read_buffer[read] = '\0';
- parse_lines (runner, runner->priv->read_buffer, read);
- }
-
- emit_rest (runner);
-
- gint status = 0;
- waitpid (runner->priv->pid, &status, 0);
-
- runner_io_exit (runner->priv->pid, status, runner);
- close_streams (runner);
-
- g_signal_emit (runner, runner_signals[END_LOADING], 0, FALSE);
-
- if (status != 0 && error)
- {
- g_set_error (error,
- GITG_RUNNER_ERROR,
- GITG_RUNNER_ERROR_EXIT,
- "Did not exit without error code");
- }
-
- return status == EXIT_SUCCESS;
+ self->priv = GITG_RUNNER_GET_PRIVATE (self);
}
-static void
-async_failed (AsyncData *data)
+GitgRunner *
+gitg_runner_new (GitgCommand *command)
{
- runner_io_exit (data->runner->priv->pid, 1, data->runner);
- close_streams (data->runner);
-
- g_signal_emit (data->runner, runner_signals[END_LOADING], 0, TRUE);
-
- async_data_free (data);
+ return g_object_new (GITG_TYPE_RUNNER,
+ "command", command,
+ NULL);
}
-static void start_reading (GitgRunner *runner, AsyncData *data);
-
static void
-read_output_ready (GInputStream *stream,
- GAsyncResult *result,
- AsyncData *data)
+splice_input_ready_cb (GOutputStream *source,
+ GAsyncResult *result,
+ AsyncData *data)
{
GError *error = NULL;
+ gboolean ret;
- gssize read = g_input_stream_read_finish (stream, result, &error);
+ ret = g_output_stream_splice_finish (source, result, &error);
if (g_cancellable_is_cancelled (data->cancellable))
{
- g_input_stream_close (stream, NULL, NULL);
- async_data_free (data);
-
if (error)
{
g_error_free (error);
}
+ async_data_free (data);
return;
}
- if (read == -1)
+ if (!ret)
{
- g_input_stream_close (stream, NULL, NULL);
- async_failed (data);
-
- if (error)
- {
- g_error_free (error);
- }
-
- return;
+ runner_done (data->runner, error);
}
- if (read == 0)
- {
- /* End */
- emit_rest (data->runner);
-
- gint status = 0;
- waitpid (data->runner->priv->pid, &status, 0);
-
- runner_io_exit (data->runner->priv->pid, status, data->runner);
- close_streams (data->runner);
-
- g_signal_emit (data->runner,
- runner_signals[END_LOADING],
- 0,
- FALSE);
-
- async_data_free (data);
- }
- else
+ if (error)
{
- data->runner->priv->read_buffer[read] = '\0';
- parse_lines (data->runner,
- data->runner->priv->read_buffer,
- read);
-
- if (g_cancellable_is_cancelled (data->cancellable))
- {
- g_input_stream_close (stream, NULL, NULL);
- async_data_free (data);
- return;
- }
-
- start_reading (data->runner, data);
+ g_error_free (error);
}
-}
-static void
-start_reading (GitgRunner *runner,
- AsyncData *data)
-{
- g_input_stream_read_async (runner->priv->input_stream,
- runner->priv->read_buffer,
- runner->priv->buffer_size,
- G_PRIORITY_DEFAULT,
- runner->priv->cancellable,
- (GAsyncReadyCallback)read_output_ready,
- data);
+ async_data_free (data);
}
static void
-write_input_ready (GOutputStream *stream, GAsyncResult *result, AsyncData *data)
+splice_output_ready_cb (GOutputStream *source,
+ GAsyncResult *result,
+ AsyncData *data)
{
GError *error = NULL;
- g_output_stream_write_finish (stream, result, &error);
+ gboolean ret;
+
+ ret = g_output_stream_splice_finish (source, result, &error);
if (g_cancellable_is_cancelled (data->cancellable))
{
@@ -695,276 +322,217 @@ write_input_ready (GOutputStream *stream, GAsyncResult *result, AsyncData *data)
}
async_data_free (data);
+ return;
}
- if (error)
+ if (!ret)
{
- async_failed (data);
- g_error_free (error);
+ runner_done (data->runner, error);
}
- else
+ else if (data->runner->priv->pid == 0)
{
- start_reading (data->runner, data);
+ runner_done (data->runner, NULL);
}
-}
-
-static gboolean
-gitg_runner_run_streams (GitgRunner *runner,
- GInputStream *input_stream,
- GOutputStream *output_stream,
- gchar const *input,
- GError **error)
-{
- gitg_runner_cancel (runner);
- if (output_stream)
+ if (error)
{
- runner->priv->output_stream = g_object_ref (output_stream);
+ g_error_free (error);
}
- if (input_stream)
- {
- GitgSmartCharsetConverter *smart;
-
- smart = gitg_smart_charset_converter_new (gitg_encoding_get_candidates ());
-
- runner->priv->input_stream = g_converter_input_stream_new (input_stream,
- G_CONVERTER (smart));
-
- g_object_unref (smart);
- }
+ async_data_free (data);
+}
- /* Emit begin-loading signal */
- g_signal_emit (runner, runner_signals[BEGIN_LOADING], 0);
+void
+gitg_runner_stream_close (GitgRunner *runner,
+ GError *error)
+{
+ g_return_if_fail (GITG_IS_RUNNER (runner));
- if (runner->priv->synchronized)
+ if (runner->priv->pid == 0 || error)
{
- return run_sync (runner, input, error);
+ runner_done (runner, error);
}
else
{
- AsyncData *data = async_data_new (runner,
- runner->priv->cancellable);
-
- if (input)
- {
- g_output_stream_write_async (runner->priv->output_stream,
- input,
- -1,
- G_PRIORITY_DEFAULT,
- runner->priv->cancellable,
- (GAsyncReadyCallback)write_input_ready,
- data);
- }
- else
- {
- start_reading (runner, data);
- }
+ g_input_stream_close (runner->priv->stdout, NULL, NULL);
}
- return TRUE;
}
-gboolean
-gitg_runner_run_with_arguments (GitgRunner *runner,
- GFile *work_tree,
- gchar const **argv,
- gchar const *input,
- GError **error)
+static void
+process_watch_cb (GPid pid,
+ gint status,
+ GitgRunner *runner)
{
- g_return_val_if_fail (GITG_IS_RUNNER (runner), FALSE);
-
- gint stdoutf;
- gint stdinf;
+ runner->priv->pid = 0;
- gitg_runner_cancel (runner);
- gchar *wd = NULL;
-
- if (work_tree)
+ if (WIFEXITED (status))
{
- wd = g_file_get_path (work_tree);
+ gitg_io_set_exit_status (GITG_IO (runner), WEXITSTATUS (status));
+ }
+ else
+ {
+ gitg_io_set_exit_status (GITG_IO (runner), 0);
}
- gboolean ret = g_spawn_async_with_pipes (wd,
- (gchar **)argv,
- runner->priv->environment,
- G_SPAWN_SEARCH_PATH |
- G_SPAWN_DO_NOT_REAP_CHILD |
- (input ? 0 : G_SPAWN_CHILD_INHERITS_STDIN) |
- (gitg_debug_enabled (GITG_DEBUG_RUNNER) ? 0 : G_SPAWN_STDERR_TO_DEV_NULL),
- NULL,
- NULL,
- &(runner->priv->pid),
- input ? &stdinf : NULL,
- &stdoutf,
- NULL,
- error);
-
- g_free (wd);
-
- if (!ret)
+ /* Note that we don't emit 'done' here because the streams might not
+ yet be ready with all their writing/reading */
+ if (runner->priv->cancellable)
{
- runner->priv->pid = 0;
- return FALSE;
+ g_object_unref (runner->priv->cancellable);
+ runner->priv->cancellable = NULL;
}
- GOutputStream *output_stream = NULL;
- GInputStream *input_stream;
+ runner->priv->watch_id = 0;
- if (input)
+ if (runner->priv->stdout == NULL || g_input_stream_is_closed (runner->priv->stdout))
{
- output_stream = G_OUTPUT_STREAM (g_unix_output_stream_new (stdinf,
- TRUE));
+ runner_done (runner, NULL);
}
+}
- input_stream = G_INPUT_STREAM (g_unix_input_stream_new (stdoutf, TRUE));
+void
+gitg_runner_run (GitgRunner *runner)
+{
+ gboolean ret;
+ gint stdinf;
+ gint stdoutf;
+ GFile *working_directory;
+ gchar *wd_path = NULL;
+ GInputStream *start_input;
+ GOutputStream *end_output;
+ GInputStream *output;
+ GitgSmartCharsetConverter *smart;
+ GError *error = NULL;
+
+ g_return_if_fail (GITG_IS_RUNNER (runner));
- ret = gitg_runner_run_streams (runner,
- input_stream,
- output_stream,
- input,
- error);
+ gitg_io_cancel (GITG_IO (runner));
- if (output_stream)
+ runner->priv->cancelled = FALSE;
+
+ working_directory = gitg_command_get_working_directory (runner->priv->command);
+
+ if (working_directory)
{
- g_object_unref (output_stream);
+ wd_path = g_file_get_path (working_directory);
+ g_object_unref (working_directory);
}
- g_object_unref (input_stream);
+ start_input = gitg_io_get_input (GITG_IO (runner));
- return ret;
-}
+ ret = g_spawn_async_with_pipes (wd_path,
+ (gchar **)gitg_command_get_arguments (runner->priv->command),
+ (gchar **)gitg_command_get_environment (runner->priv->command),
+ G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD |
+ (gitg_debug_enabled (GITG_DEBUG_RUNNER) ? 0 : G_SPAWN_STDERR_TO_DEV_NULL),
+ NULL,
+ NULL,
+ &(runner->priv->pid),
+ start_input ? &stdinf : NULL,
+ &stdoutf,
+ NULL,
+ &error);
-gboolean
-gitg_runner_run (GitgRunner *runner,
- gchar const **argv,
- GError **error)
-{
- return gitg_runner_run_with_arguments (runner, NULL, argv, NULL, error);
-}
+ g_free (wd_path);
-gboolean
-gitg_runner_run_stream (GitgRunner *runner,
- GInputStream *stream,
- GError **error)
-{
- return gitg_runner_run_streams (runner, stream, NULL, NULL, error);
-}
-
-guint
-gitg_runner_get_buffer_size (GitgRunner *runner)
-{
- g_return_val_if_fail (GITG_IS_RUNNER (runner), 0);
- return runner->priv->buffer_size;
-}
+ gitg_io_begin (GITG_IO (runner));
-static void
-dummy_cb (GPid pid,
- gint status,
- gpointer data)
-{
-}
+ if (!ret)
+ {
+ runner_done (runner, error);
+ g_error_free (error);
+ return;
+ }
-void
-gitg_runner_cancel (GitgRunner *runner)
-{
- g_return_if_fail (GITG_IS_RUNNER (runner));
+ runner->priv->watch_id = g_child_watch_add (runner->priv->pid,
+ (GChildWatchFunc)process_watch_cb,
+ runner);
- if (runner->priv->input_stream)
+ if (start_input)
{
- g_cancellable_cancel (runner->priv->cancellable);
- g_object_unref (runner->priv->cancellable);
+ AsyncData *data;
runner->priv->cancellable = g_cancellable_new ();
- if (runner->priv->pid)
- {
- g_child_watch_add (runner->priv->pid, dummy_cb, NULL);
- kill (runner->priv->pid, SIGTERM);
+ runner->priv->stdin = G_OUTPUT_STREAM (g_unix_output_stream_new (stdinf,
+ TRUE));
- runner_io_exit (runner->priv->pid, EXIT_FAILURE, runner);
- }
+ data = async_data_new (runner);
- close_streams (runner);
- g_signal_emit (runner, runner_signals[END_LOADING], 0, TRUE);
+ /* Splice the supplied input to stdin of the process */
+ g_output_stream_splice_async (runner->priv->stdin,
+ start_input,
+ G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE |
+ G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET,
+ G_PRIORITY_DEFAULT,
+ runner->priv->cancellable,
+ (GAsyncReadyCallback)splice_input_ready_cb,
+ data);
}
-}
-gboolean
-gitg_runner_running (GitgRunner *runner)
-{
- g_return_val_if_fail (GITG_IS_RUNNER (runner), FALSE);
- return runner->priv->input_stream != NULL;
-}
+ output = G_INPUT_STREAM (g_unix_input_stream_new (stdoutf,
+ TRUE));
-gint
-gitg_runner_get_exit_status (GitgRunner *runner)
-{
- g_return_val_if_fail (GITG_IS_RUNNER (runner), 1);
+ smart = gitg_smart_charset_converter_new (gitg_encoding_get_candidates ());
- return runner->priv->exit_status;
-}
+ runner->priv->stdout = g_converter_input_stream_new (output,
+ G_CONVERTER (smart));
-void
-gitg_runner_set_environment (GitgRunner *runner,
- gchar const **environment)
-{
- g_return_if_fail (GITG_IS_RUNNER (runner));
+ g_object_unref (smart);
+ g_object_unref (output);
- g_strfreev (runner->priv->environment);
+ end_output = gitg_io_get_output (GITG_IO (runner));
- if (environment == NULL)
- {
- runner->priv->environment = NULL;
- }
- else
+ if (end_output)
{
- gint len = g_strv_length ((gchar **)environment);
+ AsyncData *data;
- runner->priv->environment = g_new (gchar *, len + 1);
- gint i;
-
- for (i = 0; i < len; ++i)
+ if (runner->priv->cancellable == NULL)
{
- runner->priv->environment[i] = g_strdup (environment[i]);
+ runner->priv->cancellable = g_cancellable_new ();
}
- runner->priv->environment[len] = NULL;
+ data = async_data_new (runner);
+
+ /* Splice output of the process into the provided stream */
+ g_output_stream_splice_async (end_output,
+ runner->priv->stdout,
+ G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE |
+ G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET,
+ G_PRIORITY_DEFAULT,
+ runner->priv->cancellable,
+ (GAsyncReadyCallback)splice_output_ready_cb,
+ data);
}
}
+GInputStream *
+gitg_runner_get_stream (GitgRunner *runner)
+{
+ g_return_val_if_fail (GITG_IS_RUNNER (runner), NULL);
+
+ return runner->priv->stdout;
+}
+
void
-gitg_runner_add_environment (GitgRunner *runner,
- gchar const *key,
- gchar const *value)
+gitg_runner_set_command (GitgRunner *runner, GitgCommand *command)
{
g_return_if_fail (GITG_IS_RUNNER (runner));
- g_return_if_fail (key != NULL);
- g_return_if_fail (value != NULL);
+ g_return_if_fail (GITG_IS_COMMAND (command));
- if (runner->priv->environment == NULL)
+ if (runner->priv->command)
{
- gchar **all = g_listenv ();
-
- gint i = 0;
- runner->priv->environment = g_malloc (sizeof (gchar *) *
- (g_strv_length (all) + 1));
-
- while (all && all[i])
- {
- runner->priv->environment[i] = g_strconcat (all[i],
- "=",
- g_getenv (all[i]),
- NULL);
- ++i;
- }
-
- runner->priv->environment[i] = NULL;
+ g_object_unref (runner->priv->command);
}
- gint len = g_strv_length (runner->priv->environment);
- runner->priv->environment = g_realloc (runner->priv->environment,
- sizeof (gchar *) * (len + 2));
+ runner->priv->command = g_object_ref_sink (command);
+ g_object_notify (G_OBJECT (runner), "command");
+}
+
+GitgCommand *
+gitg_runner_get_command (GitgRunner *runner)
+{
+ g_return_val_if_fail (GITG_IS_RUNNER (runner), NULL);
- runner->priv->environment[len] = g_strconcat (key, "=", value, NULL);
- runner->priv->environment[len + 1] = NULL;
+ return runner->priv->command;
}
diff --git a/libgitg/gitg-runner.h b/libgitg/gitg-runner.h
index 589ffe1..8b02db4 100644
--- a/libgitg/gitg-runner.h
+++ b/libgitg/gitg-runner.h
@@ -1,102 +1,53 @@
-/*
- * gitg-runner.h
- * This file is part of gitg - git repository viewer
- *
- * Copyright (C) 2009 - Jesse van den Kieboom
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
#ifndef __GITG_RUNNER_H__
#define __GITG_RUNNER_H__
#include <glib-object.h>
+#include <libgitg/gitg-command.h>
+#include <libgitg/gitg-io.h>
#include <gio/gio.h>
G_BEGIN_DECLS
-#define GITG_TYPE_RUNNER (gitg_runner_get_type ())
-#define GITG_RUNNER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GITG_TYPE_RUNNER, GitgRunner))
+#define GITG_TYPE_RUNNER (gitg_runner_get_type ())
+#define GITG_RUNNER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GITG_TYPE_RUNNER, GitgRunner))
#define GITG_RUNNER_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GITG_TYPE_RUNNER, GitgRunner const))
#define GITG_RUNNER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GITG_TYPE_RUNNER, GitgRunnerClass))
-#define GITG_IS_RUNNER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GITG_TYPE_RUNNER))
+#define GITG_IS_RUNNER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GITG_TYPE_RUNNER))
#define GITG_IS_RUNNER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GITG_TYPE_RUNNER))
#define GITG_RUNNER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GITG_TYPE_RUNNER, GitgRunnerClass))
-#define GITG_RUNNER_ERROR (gitg_runner_error_quark())
-
-typedef struct _GitgRunner GitgRunner;
+typedef struct _GitgRunner GitgRunner;
typedef struct _GitgRunnerClass GitgRunnerClass;
typedef struct _GitgRunnerPrivate GitgRunnerPrivate;
-typedef enum
+struct _GitgRunner
{
- GITG_RUNNER_ERROR_NONE = 0,
- GITG_RUNNER_ERROR_EXIT
-} GitgRunnerError;
-
-struct _GitgRunner {
- GObject parent;
+ /*< private >*/
+ GitgIO parent;
GitgRunnerPrivate *priv;
+
+ /*< public >*/
};
-struct _GitgRunnerClass {
- GObjectClass parent_class;
+struct _GitgRunnerClass
+{
+ /*< private >*/
+ GitgIOClass parent_class;
- /* signals */
- void (* begin_loading) (GitgRunner *runner);
- void (* update) (GitgRunner *runner, gchar **buffer);
- void (* end_loading) (GitgRunner *runner, gboolean cancelled);
+ /*< public >*/
};
GType gitg_runner_get_type (void) G_GNUC_CONST;
-GitgRunner *gitg_runner_new (guint buffer_size);
-GitgRunner *gitg_runner_new_synchronized (guint buffer_size);
-
-guint gitg_runner_get_buffer_size (GitgRunner *runner);
-
-gboolean gitg_runner_run_stream (GitgRunner *runner,
- GInputStream *stream,
- GError **error);
-
-gboolean gitg_runner_run_with_arguments (GitgRunner *runner,
- GFile *work_tree,
- gchar const **argv,
- gchar const *input,
- GError **error);
-
-gboolean gitg_runner_run (GitgRunner *runner,
- gchar const **argv,
- GError **error);
-
-gboolean gitg_runner_running (GitgRunner *runner);
-
-gint gitg_runner_get_exit_status (GitgRunner *runner);
-void gitg_runner_cancel (GitgRunner *runner);
-
-void gitg_runner_set_environment (GitgRunner *runner, gchar const **environment);
-void gitg_runner_add_environment (GitgRunner *runner, gchar const *key, gchar const *value);
+GitgRunner *gitg_runner_new (GitgCommand *command);
-void gitg_runner_set_preserve_line_endings (GitgRunner *runner,
- gboolean preserve_line_endings);
+void gitg_runner_run (GitgRunner *runner);
-gboolean gitg_runner_get_preserve_line_endings (GitgRunner *runner);
+GitgCommand *gitg_runner_get_command (GitgRunner *runner);
+void gitg_runner_set_command (GitgRunner *runner, GitgCommand *command);
-GQuark gitg_runner_error_quark (void);
+GInputStream *gitg_runner_get_stream (GitgRunner *runner);
+void gitg_runner_stream_close (GitgRunner *runner, GError *error);
G_END_DECLS
diff --git a/libgitg/gitg-shell.c b/libgitg/gitg-shell.c
new file mode 100644
index 0000000..9d8937b
--- /dev/null
+++ b/libgitg/gitg-shell.c
@@ -0,0 +1,1052 @@
+/*
+ * gitg-shell.c
+ * This file is part of gitg - git repository viewer
+ *
+ * Copyright (C) 2009 - Jesse van den Kieboom
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "gitg-convert.h"
+#include "gitg-debug.h"
+#include "gitg-shell.h"
+#include "gitg-smart-charset-converter.h"
+#include "gitg-runner.h"
+
+#include <string.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <errno.h>
+#include <stdlib.h>
+
+#include <gio/gio.h>
+#include <gio/gunixoutputstream.h>
+#include <gio/gunixinputstream.h>
+
+#include "gitg-line-parser.h"
+
+#define GITG_SHELL_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE((object), GITG_TYPE_SHELL, GitgShellPrivate))
+
+/* Signals */
+enum
+{
+ UPDATE,
+ LAST_SIGNAL
+};
+
+static guint shell_signals[LAST_SIGNAL] = { 0 };
+
+/* Properties */
+enum
+{
+ PROP_0,
+
+ PROP_BUFFER_SIZE,
+ PROP_SYNCHRONIZED,
+ PROP_PRESERVE_LINE_ENDINGS
+};
+
+struct _GitgShellPrivate
+{
+ GSList *runners;
+
+ GCancellable *cancellable;
+ GError *error;
+
+ GMainLoop *main_loop;
+ GitgRunner *last_runner;
+
+ guint buffer_size;
+ GitgLineParser *line_parser;
+
+ guint synchronized : 1;
+ guint preserve_line_endings : 1;
+ guint cancelled : 1;
+ guint read_done : 1;
+};
+
+static void shell_done (GitgShell *shell, GError *error);
+
+G_DEFINE_TYPE (GitgShell, gitg_shell, GITG_TYPE_IO)
+
+static void
+runner_end (GitgRunner *runner,
+ GError *error,
+ GitgShell *shell)
+{
+ if (!shell->priv->runners)
+ {
+ return;
+ }
+
+ if ((runner == shell->priv->last_runner && shell->priv->read_done) || error)
+ {
+ shell_done (shell, error);
+ }
+}
+
+static void
+close_runners (GitgShell *shell)
+{
+ GSList *item;
+
+ for (item = shell->priv->runners; item; item = g_slist_next (item))
+ {
+ GitgRunner *runner = item->data;
+
+ g_signal_handlers_disconnect_by_func (runner,
+ runner_end,
+ shell);
+
+ gitg_io_close (GITG_IO (runner));
+ g_object_unref (runner);
+ }
+
+ g_slist_free (shell->priv->runners);
+ shell->priv->runners = NULL;
+
+ if (shell->priv->line_parser)
+ {
+ g_object_unref (shell->priv->line_parser);
+ shell->priv->line_parser = NULL;
+ }
+
+ shell->priv->last_runner = NULL;
+}
+
+static void
+gitg_shell_finalize (GObject *object)
+{
+ GitgShell *shell = GITG_SHELL (object);
+
+ /* Cancel possible running */
+ gitg_io_cancel (GITG_IO (shell));
+
+ if (shell->priv->cancellable)
+ {
+ g_object_unref (shell->priv->cancellable);
+ }
+
+ G_OBJECT_CLASS (gitg_shell_parent_class)->finalize (object);
+}
+
+static void
+gitg_shell_dispose (GObject *object)
+{
+ GitgShell *shell;
+
+ shell = GITG_SHELL (object);
+
+ close_runners (shell);
+}
+
+static void
+gitg_shell_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GitgShell *shell = GITG_SHELL (object);
+
+ switch (prop_id)
+ {
+ case PROP_BUFFER_SIZE:
+ g_value_set_uint (value, shell->priv->buffer_size);
+ break;
+ case PROP_SYNCHRONIZED:
+ g_value_set_boolean (value, shell->priv->synchronized);
+ break;
+ case PROP_PRESERVE_LINE_ENDINGS:
+ g_value_set_boolean (value, shell->priv->preserve_line_endings);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gitg_shell_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GitgShell *shell = GITG_SHELL (object);
+
+ switch (prop_id)
+ {
+ case PROP_BUFFER_SIZE:
+ shell->priv->buffer_size = g_value_get_uint (value);
+ break;
+ case PROP_SYNCHRONIZED:
+ shell->priv->synchronized = g_value_get_boolean (value);
+ break;
+ case PROP_PRESERVE_LINE_ENDINGS:
+ shell->priv->preserve_line_endings = g_value_get_boolean (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gitg_shell_cancel (GitgIO *io)
+{
+ gboolean was_running;
+ GitgShell *shell;
+
+ shell = GITG_SHELL (io);
+
+ if (shell->priv->line_parser)
+ {
+ g_object_unref (shell->priv->line_parser);
+ shell->priv->line_parser = NULL;
+ }
+
+ was_running = gitg_io_get_running (io);
+
+ GITG_IO_CLASS (gitg_shell_parent_class)->cancel (io);
+
+ if (was_running)
+ {
+ shell_done (GITG_SHELL (io), NULL);
+ }
+}
+
+static void
+gitg_shell_class_init (GitgShellClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GitgIOClass *io_class = GITG_IO_CLASS (klass);
+
+ object_class->finalize = gitg_shell_finalize;
+ object_class->dispose = gitg_shell_dispose;
+
+ object_class->get_property = gitg_shell_get_property;
+ object_class->set_property = gitg_shell_set_property;
+
+ io_class->cancel = gitg_shell_cancel;
+
+ g_object_class_install_property (object_class, PROP_BUFFER_SIZE,
+ g_param_spec_uint ("buffer_size",
+ "BUFFER SIZE",
+ "The shells buffer size",
+ 1,
+ G_MAXUINT,
+ 1,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+
+ g_object_class_install_property (object_class, PROP_SYNCHRONIZED,
+ g_param_spec_boolean ("synchronized",
+ "SYNCHRONIZED",
+ "Whether the command is ran synchronized",
+ FALSE,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+
+ g_object_class_install_property (object_class,
+ PROP_PRESERVE_LINE_ENDINGS,
+ g_param_spec_boolean ("preserve-line-endings",
+ "Preserve Line Endings",
+ "preserve line endings",
+ FALSE,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+
+ shell_signals[UPDATE] =
+ g_signal_new ("update",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GitgShellClass, update),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__POINTER,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_POINTER);
+
+ g_type_class_add_private (object_class, sizeof (GitgShellPrivate));
+}
+
+static void
+gitg_shell_init (GitgShell *self)
+{
+ self->priv = GITG_SHELL_GET_PRIVATE (self);
+
+ self->priv->cancellable = g_cancellable_new ();
+}
+
+GitgShell *
+gitg_shell_new (guint buffer_size)
+{
+ g_assert (buffer_size > 0);
+
+ return GITG_SHELL (g_object_new (GITG_TYPE_SHELL,
+ "buffer_size",
+ buffer_size,
+ "synchronized",
+ FALSE,
+ NULL));
+}
+
+GitgShell *
+gitg_shell_new_synchronized (guint buffer_size)
+{
+ g_assert (buffer_size > 0);
+
+ return GITG_SHELL (g_object_new (GITG_TYPE_SHELL,
+ "buffer_size",
+ buffer_size,
+ "synchronized",
+ TRUE,
+ NULL));
+}
+
+void
+gitg_shell_set_preserve_line_endings (GitgShell *shell,
+ gboolean preserve_line_endings)
+{
+ g_return_if_fail (GITG_IS_SHELL (shell));
+
+ shell->priv->preserve_line_endings = preserve_line_endings;
+ g_object_notify (G_OBJECT (shell), "preserve-line-endings");
+}
+
+gboolean
+gitg_shell_get_preserve_line_endings (GitgShell *shell)
+{
+ g_return_val_if_fail (GITG_IS_SHELL (shell), FALSE);
+
+ return shell->priv->preserve_line_endings;
+}
+
+static void
+shell_done (GitgShell *shell,
+ GError *error)
+{
+ if (shell->priv->error)
+ {
+ g_error_free (shell->priv->error);
+ shell->priv->error = NULL;
+ }
+
+ if (error)
+ {
+ shell->priv->error = g_error_copy (error);
+ gitg_io_set_exit_status (GITG_IO (shell), EXIT_FAILURE);
+ }
+
+ if (shell->priv->main_loop)
+ {
+ g_main_loop_quit (shell->priv->main_loop);
+ g_main_loop_unref (shell->priv->main_loop);
+
+ shell->priv->main_loop = NULL;
+ }
+
+ if (shell->priv->runners == NULL)
+ {
+ return;
+ }
+
+ if (shell->priv->cancellable)
+ {
+ g_cancellable_cancel (shell->priv->cancellable);
+ g_object_unref (shell->priv->cancellable);
+
+ shell->priv->cancellable = NULL;
+ }
+
+ /* Take over the exit code of the last runner */
+ if (!error)
+ {
+ gitg_io_set_exit_status (GITG_IO (shell),
+ gitg_io_get_exit_status (GITG_IO (shell->priv->last_runner)));
+ }
+
+ close_runners (shell);
+ gitg_io_close (GITG_IO (shell));
+
+ gitg_io_end (GITG_IO (shell), error);
+}
+
+static gboolean
+run_sync (GitgShell *shell,
+ GError **error)
+{
+ g_main_loop_run (shell->priv->main_loop);
+
+ if (shell->priv->error)
+ {
+ g_propagate_error (error, shell->priv->error);
+ shell->priv->error = NULL;
+
+ return FALSE;
+ }
+
+ return gitg_io_get_exit_status (GITG_IO (shell)) == 0;
+}
+
+static void
+on_lines_done_cb (GitgLineParser *parser,
+ GError *error,
+ GitgShell *shell)
+{
+ if (!shell->priv->read_done)
+ {
+ shell->priv->read_done = TRUE;
+
+ if (shell->priv->last_runner == NULL)
+ {
+ shell_done (shell, error);
+ }
+ else
+ {
+ gitg_runner_stream_close (shell->priv->last_runner, NULL);
+ }
+ }
+}
+
+static void
+on_lines_cb (GitgLineParser *parser,
+ gchar **lines,
+ GitgShell *shell)
+{
+ g_signal_emit (shell, shell_signals[UPDATE], 0, lines);
+}
+
+static void
+run_stream (GitgShell *shell,
+ GInputStream *stream)
+{
+ shell->priv->cancellable = g_cancellable_new ();
+
+ shell->priv->read_done = FALSE;
+
+ shell->priv->line_parser = gitg_line_parser_new (shell->priv->buffer_size,
+ shell->priv->preserve_line_endings);
+
+ g_signal_connect (shell->priv->line_parser,
+ "lines",
+ G_CALLBACK (on_lines_cb),
+ shell);
+
+ g_signal_connect (shell->priv->line_parser,
+ "done",
+ G_CALLBACK (on_lines_done_cb),
+ shell);
+
+ gitg_line_parser_parse (shell->priv->line_parser,
+ stream,
+ shell->priv->cancellable);
+}
+
+static gboolean
+run_commands (GitgShell *shell,
+ GitgCommand **commands,
+ GError **error)
+{
+ GitgIO *io;
+ GitgRunner *prev = NULL;
+ GOutputStream *output;
+ gboolean ret = TRUE;
+ GitgCommand **ptr;
+
+ io = GITG_IO (shell);
+ output = gitg_io_get_output (io);
+
+ shell->priv->read_done = TRUE;
+
+ gitg_io_cancel (GITG_IO (shell));
+
+ gitg_io_begin (GITG_IO (shell));
+
+ /* Ref sink all commands */
+ for (ptr = commands; *ptr; ++ptr)
+ {
+ g_object_ref_sink (*ptr);
+ }
+
+ if (shell->priv->synchronized)
+ {
+ shell->priv->main_loop = g_main_loop_new (NULL, FALSE);
+ }
+
+ /* Setup runners */
+ for (ptr = commands; *ptr; ++ptr)
+ {
+ GitgRunner *runner;
+
+ runner = gitg_runner_new (*ptr);
+
+ g_signal_connect (runner,
+ "end",
+ G_CALLBACK (runner_end),
+ shell);
+
+ if (ptr == commands)
+ {
+ /* Copy input set on the shell to the first runner */
+ GInputStream *input;
+
+ input = gitg_io_get_input (io);
+
+ if (input != NULL)
+ {
+ gitg_io_set_input (GITG_IO (runner), input);
+ }
+ }
+ else
+ {
+ /* Set output of the previous runner to the input of
+ this runner */
+ gitg_io_set_input (GITG_IO (runner),
+ gitg_runner_get_stream (prev));
+ }
+
+ if (!*(ptr + 1))
+ {
+ shell->priv->last_runner = runner;
+
+ /* Copy output set on the shell to the last runner */
+ if (output != NULL)
+ {
+ gitg_io_set_output (GITG_IO (runner), output);
+ }
+ }
+
+ shell->priv->runners = g_slist_append (shell->priv->runners,
+ runner);
+
+ /* Start the runner */
+ gitg_runner_run (runner);
+
+ if (shell->priv->runners == NULL)
+ {
+ /* This means it there was an error */
+ if (error && shell->priv->error)
+ {
+ *error = g_error_copy (shell->priv->error);
+ }
+
+ if (shell->priv->error)
+ {
+ g_error_free (shell->priv->error);
+ shell->priv->error = NULL;
+ }
+
+ ret = FALSE;
+ goto cleanup;
+ }
+
+ prev = runner;
+ }
+
+ /* Setup line reader if necessary in async mode */
+ if (output == NULL)
+ {
+ run_stream (shell, gitg_runner_get_stream (shell->priv->last_runner));
+ }
+
+ if (shell->priv->synchronized)
+ {
+ return run_sync (shell, error);
+ }
+
+cleanup:
+ for (ptr = commands; *ptr; ++ptr)
+ {
+ g_object_unref (*ptr);
+ }
+
+ if (shell->priv->main_loop)
+ {
+ g_main_loop_unref (shell->priv->main_loop);
+ shell->priv->main_loop = NULL;
+ }
+
+ return ret;
+}
+
+gboolean
+gitg_shell_run (GitgShell *shell,
+ GitgCommand *command,
+ GError **error)
+{
+ g_return_val_if_fail (GITG_IS_SHELL (shell), FALSE);
+ g_return_val_if_fail (GITG_IS_COMMAND (command), FALSE);
+
+ return gitg_shell_runv (shell, error, command, NULL);
+}
+
+gboolean
+gitg_shell_run_list (GitgShell *shell,
+ GitgCommand **commands,
+ GError **error)
+{
+ g_return_val_if_fail (GITG_IS_SHELL (shell), FALSE);
+
+ return run_commands (shell, commands, error);
+}
+
+gboolean
+gitg_shell_runva (GitgShell *shell,
+ va_list ap,
+ GError **error)
+{
+ GPtrArray *ptr;
+ GitgCommand **commands;
+ GitgCommand *command;
+ gboolean ret;
+ guint num = 0;
+
+ g_return_val_if_fail (GITG_IS_SHELL (shell), FALSE);
+
+ ptr = g_ptr_array_new ();
+
+ while ((command = va_arg (ap, GitgCommand *)) != NULL)
+ {
+ g_ptr_array_add (ptr, command);
+ ++num;
+ }
+
+ if (num == 0)
+ {
+ g_ptr_array_free (ptr, TRUE);
+ return FALSE;
+ }
+
+ g_ptr_array_add (ptr, NULL);
+
+ commands = (GitgCommand **)g_ptr_array_free (ptr, FALSE);
+
+ ret = gitg_shell_run_list (shell, commands, error);
+
+ g_free (commands);
+
+ return ret;
+}
+
+gboolean
+gitg_shell_runv (GitgShell *shell,
+ GError **error,
+ ...)
+{
+ va_list ap;
+ gboolean ret;
+
+ g_return_val_if_fail (GITG_IS_SHELL (shell), FALSE);
+
+ va_start (ap, error);
+ ret = gitg_shell_runva (shell, ap, error);
+ va_end (ap);
+
+ return ret;
+}
+
+guint
+gitg_shell_get_buffer_size (GitgShell *shell)
+{
+ g_return_val_if_fail (GITG_IS_SHELL (shell), 0);
+ return shell->priv->buffer_size;
+}
+
+gchar **
+gitg_shell_run_sync_with_output (GitgCommand *command,
+ gboolean preserve_line_endings,
+ GError **error)
+{
+ g_return_val_if_fail (GITG_IS_COMMAND (command), NULL);
+
+ return gitg_shell_run_sync_with_outputv (preserve_line_endings,
+ error,
+ command,
+ NULL);
+}
+
+static void
+collect_update (GitgShell *shell,
+ gchar const * const *lines,
+ GPtrArray *ret)
+{
+ while (lines && *lines)
+ {
+ g_ptr_array_add (ret, g_strdup (*lines++));
+ }
+}
+
+gchar **
+gitg_shell_run_sync_with_input_and_output_list (GitgCommand **commands,
+ gboolean preserve_line_endings,
+ const gchar *input,
+ GError **error)
+{
+ GitgShell *shell;
+ GPtrArray *ret;
+ gboolean res;
+ gchar **val;
+
+ shell = gitg_shell_new_synchronized (1000);
+
+ gitg_shell_set_preserve_line_endings (shell, preserve_line_endings);
+
+ ret = g_ptr_array_sized_new (100);
+
+ g_signal_connect (shell,
+ "update",
+ G_CALLBACK (collect_update),
+ ret);
+
+ if (input)
+ {
+ GInputStream *stream;
+
+ stream = g_memory_input_stream_new_from_data (g_strdup (input),
+ -1,
+ (GDestroyNotify)g_free);
+
+ gitg_io_set_input (GITG_IO (shell), stream);
+ g_object_unref (stream);
+ }
+
+ res = gitg_shell_run_list (shell, commands, error);
+
+ g_ptr_array_add (ret, NULL);
+
+ if (!res || gitg_io_get_exit_status (GITG_IO (shell)) != 0)
+ {
+ g_strfreev ((gchar **)g_ptr_array_free (ret, FALSE));
+ g_object_unref (shell);
+
+ return NULL;
+ }
+
+ val = (gchar **)g_ptr_array_free (ret, FALSE);
+ g_object_unref (shell);
+
+ return val;
+
+}
+
+static gchar **
+gitg_shell_run_sync_with_input_and_outputva (gboolean preserve_line_endings,
+ const gchar *input,
+ va_list ap,
+ GError **error)
+{
+ GPtrArray *commands;
+ GitgCommand *cmd;
+ GitgCommand **cmds;
+ gchar **ret;
+
+ commands = g_ptr_array_new ();
+
+ while ((cmd = va_arg (ap, GitgCommand *)))
+ {
+ g_ptr_array_add (commands, cmd);
+ }
+
+ g_ptr_array_add (commands, NULL);
+ cmds = (GitgCommand **)g_ptr_array_free (commands, FALSE);
+
+ ret = gitg_shell_run_sync_with_input_and_output_list (cmds,
+ preserve_line_endings,
+ input,
+ error);
+
+ g_free (cmds);
+ return ret;
+}
+
+static gchar **
+gitg_shell_run_sync_with_outputva (gboolean preserve_line_endings,
+ va_list ap,
+ GError **error)
+{
+ return gitg_shell_run_sync_with_input_and_outputva (preserve_line_endings,
+ NULL,
+ ap,
+ error);
+}
+
+gchar **
+gitg_shell_run_sync_with_output_list (GitgCommand **commands,
+ gboolean preserve_line_endings,
+ GError **error)
+{
+ return gitg_shell_run_sync_with_input_and_output_list (commands,
+ preserve_line_endings,
+ NULL,
+ error);
+}
+
+gchar **
+gitg_shell_run_sync_with_outputv (gboolean preserve_line_endings,
+ GError **error,
+ ...)
+{
+ va_list ap;
+ gchar **ret;
+
+ va_start (ap, error);
+ ret = gitg_shell_run_sync_with_outputva (preserve_line_endings,
+ ap,
+ error);
+ va_end (ap);
+
+ return ret;
+}
+
+gboolean
+gitg_shell_run_sync (GitgCommand *command,
+ GError **error)
+{
+ g_return_val_if_fail (GITG_IS_COMMAND (command), FALSE);
+
+ return gitg_shell_run_syncv (error, command, NULL);
+}
+
+gboolean
+gitg_shell_run_sync_list (GitgCommand **commands,
+ GError **error)
+{
+ gchar **res;
+
+ res = gitg_shell_run_sync_with_output_list (commands, FALSE, error);
+
+ if (res)
+ {
+ g_strfreev (res);
+ return TRUE;
+ }
+ else
+ {
+ return FALSE;
+ }
+}
+
+gboolean
+gitg_shell_run_syncv (GError **error,
+ ...)
+{
+ va_list ap;
+ gchar **res;
+
+ va_start (ap, error);
+ res = gitg_shell_run_sync_with_outputva (FALSE, ap, error);
+ va_end (ap);
+
+ if (res)
+ {
+ g_strfreev (res);
+ return TRUE;
+ }
+ else
+ {
+ return FALSE;
+ }
+}
+
+gboolean
+gitg_shell_run_sync_with_input (GitgCommand *command,
+ const gchar *input,
+ GError **error)
+{
+ g_return_val_if_fail (GITG_IS_COMMAND (command), FALSE);
+
+ return gitg_shell_run_sync_with_inputv (input, error, command, NULL);
+}
+
+gboolean
+gitg_shell_run_sync_with_input_list (GitgCommand **commands,
+ const gchar *input,
+ GError **error)
+{
+ gchar **ret;
+
+ ret = gitg_shell_run_sync_with_input_and_output_list (commands,
+ FALSE,
+ input,
+ error);
+
+ if (ret)
+ {
+ g_strfreev (ret);
+ return TRUE;
+ }
+ else
+ {
+ return FALSE;
+ }
+}
+
+gboolean
+gitg_shell_run_sync_with_inputv (const gchar *input,
+ GError **error,
+ ...)
+{
+ va_list ap;
+ gchar **ret;
+
+ va_start (ap, error);
+ ret = gitg_shell_run_sync_with_input_and_outputva (FALSE,
+ input,
+ ap,
+ error);
+ va_end (ap);
+
+ if (ret)
+ {
+ g_strfreev (ret);
+ return TRUE;
+ }
+ else
+ {
+ return FALSE;
+ }
+}
+
+gchar **
+gitg_shell_run_sync_with_input_and_output (GitgCommand *command,
+ gboolean preserve_line_endings,
+ const gchar *input,
+ GError **error)
+{
+ g_return_val_if_fail (GITG_IS_COMMAND (command), NULL);
+
+ return gitg_shell_run_sync_with_input_and_outputv (preserve_line_endings,
+ input,
+ error,
+ command,
+ NULL);
+}
+
+gchar **
+gitg_shell_run_sync_with_input_and_outputv (gboolean preserve_line_endings,
+ const gchar *input,
+ GError **error,
+ ...)
+{
+ va_list ap;
+ gchar **ret;
+
+ va_start (ap, error);
+ ret = gitg_shell_run_sync_with_input_and_outputva (preserve_line_endings,
+ input,
+ ap,
+ error);
+ va_end (ap);
+
+ return ret;
+}
+
+GitgCommand **
+gitg_shell_parse_commands (GitgRepository *repository,
+ const gchar *cmdstr,
+ GError **error)
+{
+ gint argc;
+ gchar **argv;
+ GitgCommand *cmd = NULL;
+ gint i;
+ GPtrArray *commands;
+ gboolean canenv = TRUE;
+ guint num = 0;
+
+ g_return_val_if_fail (repository == NULL || GITG_IS_REPOSITORY (repository), NULL);
+ g_return_val_if_fail (cmdstr != NULL, NULL);
+
+ if (!g_shell_parse_argv (cmdstr, &argc, &argv, error))
+ {
+ return FALSE;
+ }
+
+ commands = g_ptr_array_new ();
+
+ for (i = 0; i < argc; ++i)
+ {
+ gchar *pos;
+
+ if (cmd == NULL)
+ {
+ cmd = gitg_command_newv (repository, NULL);
+ g_ptr_array_add (commands, cmd);
+
+ canenv = TRUE;
+ ++num;
+ }
+
+ if (strcmp (argv[i], "|") == 0)
+ {
+ cmd = NULL;
+ }
+ else if (canenv && (pos = g_utf8_strchr (argv[i], -1, '=')))
+ {
+ *pos = '\0';
+ gitg_command_add_environmentv (cmd, argv[i], pos + 1, NULL);
+ }
+ else
+ {
+ canenv = FALSE;
+ gitg_command_add_argumentsv (cmd, argv[i], NULL);
+ }
+ }
+
+ g_strfreev (argv);
+ g_ptr_array_add (commands, NULL);
+
+ return (GitgCommand **)g_ptr_array_free (commands, FALSE);
+}
+
+gboolean
+gitg_shell_run_parse (GitgShell *shell,
+ GitgRepository *repository,
+ const gchar *cmdstr,
+ GError **error)
+
+{
+ gboolean ret;
+ GitgCommand **commands;
+
+ g_return_val_if_fail (GITG_IS_SHELL (shell), FALSE);
+ g_return_val_if_fail (cmdstr != NULL, FALSE);
+ g_return_val_if_fail (repository == NULL || GITG_IS_REPOSITORY (repository), FALSE);
+
+ commands = gitg_shell_parse_commands (repository, cmdstr, error);
+
+ if (!commands)
+ {
+ return FALSE;
+ }
+
+ ret = run_commands (shell, commands, error);
+ g_free (commands);
+
+ return ret;
+}
+
+gboolean
+gitg_shell_run_stream (GitgShell *shell,
+ GInputStream *stream,
+ GError **error)
+{
+ g_return_val_if_fail (GITG_IS_SHELL (shell), FALSE);
+ g_return_val_if_fail (G_IS_INPUT_STREAM (stream), FALSE);
+
+ gitg_io_cancel (GITG_IO (shell));
+
+ run_stream (shell, stream);
+ return TRUE;
+}
diff --git a/libgitg/gitg-shell.h b/libgitg/gitg-shell.h
new file mode 100644
index 0000000..69b0502
--- /dev/null
+++ b/libgitg/gitg-shell.h
@@ -0,0 +1,153 @@
+/*
+ * gitg-shell.h
+ * This file is part of gitg - git repository viewer
+ *
+ * Copyright (C) 2009 - Jesse van den Kieboom
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GITG_SHELL_H__
+#define __GITG_SHELL_H__
+
+#include <glib-object.h>
+#include <libgitg/gitg-io.h>
+#include <libgitg/gitg-command.h>
+#include <libgitg/gitg-repository.h>
+
+G_BEGIN_DECLS
+
+#define GITG_TYPE_SHELL (gitg_shell_get_type ())
+#define GITG_SHELL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GITG_TYPE_SHELL, GitgShell))
+#define GITG_SHELL_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GITG_TYPE_SHELL, GitgShell const))
+#define GITG_SHELL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GITG_TYPE_SHELL, GitgShellClass))
+#define GITG_IS_SHELL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GITG_TYPE_SHELL))
+#define GITG_IS_SHELL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GITG_TYPE_SHELL))
+#define GITG_SHELL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GITG_TYPE_SHELL, GitgShellClass))
+
+#define GITG_SHELL_ERROR (gitg_shell_error_quark())
+
+typedef struct _GitgShell GitgShell;
+typedef struct _GitgShellClass GitgShellClass;
+typedef struct _GitgShellPrivate GitgShellPrivate;
+
+struct _GitgShell
+{
+ GitgIO parent;
+
+ GitgShellPrivate *priv;
+};
+
+struct _GitgShellClass
+{
+ GitgIOClass parent_class;
+
+ /* signals */
+ void (* update) (GitgShell *shell,
+ gchar const * const *buffer);
+};
+
+GType gitg_shell_get_type (void) G_GNUC_CONST;
+
+GitgShell *gitg_shell_new (guint buffer_size);
+GitgShell *gitg_shell_new_synchronized (guint buffer_size);
+
+void gitg_shell_set_preserve_line_endings (GitgShell *shell,
+ gboolean preserve_line_endings);
+gboolean gitg_shell_get_preserve_line_endings (GitgShell *shell);
+
+guint gitg_shell_get_buffer_size (GitgShell *shell);
+
+GitgCommand **gitg_shell_parse_commands (GitgRepository *repository,
+ const gchar *cmdstr,
+ GError **error);
+
+gboolean gitg_shell_run_parse (GitgShell *shell,
+ GitgRepository *repository,
+ const gchar *cmd,
+ GError **error);
+
+gboolean gitg_shell_runva (GitgShell *shell,
+ va_list ap,
+ GError **error);
+
+gboolean gitg_shell_run_stream (GitgShell *shell,
+ GInputStream *stream,
+ GError **error);
+
+gboolean gitg_shell_run (GitgShell *shell,
+ GitgCommand *command,
+ GError **error);
+
+gboolean gitg_shell_run_list (GitgShell *shell,
+ GitgCommand **commands,
+ GError **error);
+
+gboolean gitg_shell_runv (GitgShell *shell,
+ GError **error,
+ ...) G_GNUC_NULL_TERMINATED;
+
+gchar **gitg_shell_run_sync_with_output (GitgCommand *command,
+ gboolean preserve_line_endings,
+ GError **error);
+
+gchar **gitg_shell_run_sync_with_output_list (GitgCommand **commands,
+ gboolean preserve_line_endings,
+ GError **error);
+
+gchar **gitg_shell_run_sync_with_outputv (gboolean preserve_line_endings,
+ GError **error,
+ ...) G_GNUC_NULL_TERMINATED;
+
+gboolean gitg_shell_run_sync (GitgCommand *command,
+ GError **error);
+
+gboolean gitg_shell_run_sync_list (GitgCommand **commands,
+ GError **error);
+
+gboolean gitg_shell_run_syncv (GError **error,
+ ...) G_GNUC_NULL_TERMINATED;
+
+gboolean gitg_shell_run_sync_with_input (GitgCommand *command,
+ const gchar *input,
+ GError **error);
+
+gboolean gitg_shell_run_sync_with_input_list (GitgCommand **commands,
+ const gchar *input,
+ GError **error);
+
+gboolean gitg_shell_run_sync_with_inputv (const gchar *input,
+ GError **error,
+ ...) G_GNUC_NULL_TERMINATED;
+
+gchar **gitg_shell_run_sync_with_input_and_output (GitgCommand *command,
+ gboolean preserve_line_endings,
+ const gchar *input,
+ GError **error);
+
+gchar **gitg_shell_run_sync_with_input_and_output_list (GitgCommand **commands,
+ gboolean preserve_line_endings,
+ const gchar *input,
+ GError **error);
+
+gchar **gitg_shell_run_sync_with_input_and_outputv (gboolean preserve_line_endings,
+ const gchar *input,
+ GError **error,
+ ...) G_GNUC_NULL_TERMINATED;
+
+G_END_DECLS
+
+#endif /* __GITG_SHELL_H__ */
diff --git a/tests/Makefile.am b/tests/Makefile.am
new file mode 100644
index 0000000..d7ca32d
--- /dev/null
+++ b/tests/Makefile.am
@@ -0,0 +1,12 @@
+INCLUDES = -g -I$(top_srcdir) -I$(top_srcdir)/gitg -I$(top_srcdir)/libgitg $(GITG_DEBUG_FLAGS) $(GITG_CFLAGS)
+
+noinst_PROGRAMS = $(TEST_PROGS)
+progs_ldadd = $(top_builddir)/libgitg/libgitg-1.0.la
+
+TEST_PROGS = shell
+shell_SOURCES = shell.c
+shell_LDADD = $(progs_ldadd)
+
+TESTS = $(TEST_PROGS)
+
+-include $(top_srcdir)/git.mk
diff --git a/tests/shell.c b/tests/shell.c
new file mode 100644
index 0000000..04d2e5b
--- /dev/null
+++ b/tests/shell.c
@@ -0,0 +1,273 @@
+#include <libgitg/gitg-shell.h>
+#include <string.h>
+
+#define test_add_repo(name, callback) g_test_add (name, RepositoryInfo, NULL, repository_setup, callback, repository_cleanup)
+
+typedef struct
+{
+ GitgRepository *repository;
+} RepositoryInfo;
+
+static gboolean
+remove_all (gchar const *path,
+ GError **error)
+{
+ gchar const *argv[] = {
+ "rm",
+ "-rf",
+ path,
+ NULL
+ };
+
+ g_spawn_sync ("/",
+ (gchar **)argv,
+ NULL,
+ G_SPAWN_SEARCH_PATH |
+ G_SPAWN_STDOUT_TO_DEV_NULL |
+ G_SPAWN_STDERR_TO_DEV_NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ error);
+}
+
+static void
+repository_setup (RepositoryInfo *info,
+ gconstpointer data)
+{
+ /* Create repository */
+ gchar const *tmp = g_get_tmp_dir ();
+ gchar *repo_path;
+ GError *error = NULL;
+
+ repo_path = g_build_filename (tmp, "gitg-test-repo", NULL);
+
+ if (g_file_test (repo_path, G_FILE_TEST_EXISTS))
+ {
+ remove_all (repo_path, &error);
+
+ g_assert_no_error (error);
+ }
+
+ g_assert (g_mkdir (repo_path, 0700) == 0);
+
+ gchar const *argv[] = {
+ "git",
+ "init",
+ NULL,
+ NULL,
+ NULL
+ };
+
+ g_spawn_sync (repo_path,
+ (gchar **)argv,
+ NULL,
+ G_SPAWN_SEARCH_PATH |
+ G_SPAWN_STDOUT_TO_DEV_NULL |
+ G_SPAWN_STDERR_TO_DEV_NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ &error);
+
+ g_assert_no_error (error);
+
+ argv[0] = "/bin/bash";
+ argv[1] = "-c";
+ argv[2] = "echo haha > test.txt && git add test.txt && git commit -m 'Initial import'";
+
+ g_spawn_sync (repo_path,
+ (gchar **)argv,
+ NULL,
+ G_SPAWN_STDOUT_TO_DEV_NULL |
+ G_SPAWN_STDERR_TO_DEV_NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ &error);
+
+ g_assert_no_error (error);
+
+ GFile *work_tree = g_file_new_for_path (repo_path);
+ gchar *git_dir_path = g_build_filename (repo_path, ".git", NULL);
+ GFile *git_dir = g_file_new_for_path (git_dir_path);
+ g_free (git_dir_path);
+
+ info->repository = gitg_repository_new (git_dir, work_tree);
+
+ g_object_unref (work_tree);
+ g_object_unref (git_dir);
+}
+
+static void
+repository_cleanup (RepositoryInfo *info,
+ gconstpointer data)
+{
+ GFile *work_tree;
+ GError *error = NULL;
+
+ work_tree = gitg_repository_get_work_tree (info->repository);
+ gchar *path = g_file_get_path (work_tree);
+ g_object_unref (work_tree);
+
+ remove_all (path, &error);
+ g_free (path);
+
+ g_assert_no_error (error);
+
+ g_object_unref (info->repository);
+}
+
+static void
+test_success (RepositoryInfo *info,
+ gconstpointer data)
+{
+ gboolean ret;
+ GError *error = NULL;
+
+ ret = gitg_shell_run_sync (gitg_command_newv (info->repository,
+ "rev-parse",
+ "HEAD",
+ NULL),
+ &error);
+
+ g_assert_no_error (error);
+ g_assert (ret);
+}
+
+static void
+test_fail (RepositoryInfo *info,
+ gconstpointer data)
+{
+ gboolean ret;
+ GError *error = NULL;
+
+ ret = gitg_shell_run_sync (gitg_command_newv (info->repository,
+ "bogus",
+ NULL),
+ &error);
+
+ g_assert (!ret);
+ g_assert (error != NULL);
+
+ g_error_free (error);
+}
+
+static void
+test_output (RepositoryInfo *info,
+ gconstpointer data)
+{
+ gchar **ret;
+ GError *error = NULL;
+
+ ret = gitg_shell_run_sync_with_output (gitg_command_newv (info->repository,
+ "rev-parse",
+ "HEAD",
+ NULL),
+ FALSE,
+ &error);
+
+ g_assert_no_error (error);
+
+ g_assert (ret);
+ g_assert (g_strv_length (ret) == 1);
+
+ g_assert (strlen (ret[0]) == 40);
+}
+
+static void
+test_input (void)
+{
+ gchar **ret;
+ gchar const *input = "Hello world";
+ GError *error = NULL;
+
+ ret = gitg_shell_run_sync_with_input_and_output (gitg_command_newv (NULL,
+ "cat",
+ "-",
+ NULL),
+ FALSE,
+ input,
+ &error);
+
+ g_assert_no_error (error);
+ g_assert (ret);
+
+ g_assert (g_strv_length (ret) == 1);
+ g_assert_cmpstr (ret[0], ==, input);
+}
+
+static void
+test_pipe (void)
+{
+ gchar **ret;
+ GError *error = NULL;
+ gchar const *input = "Hello world";
+
+ ret = gitg_shell_run_sync_with_outputv (FALSE,
+ &error,
+ gitg_command_newv (NULL, "echo", input, NULL),
+ gitg_command_newv (NULL, "cat", "-", NULL),
+ NULL);
+
+ g_assert_no_error (error);
+ g_assert (ret);
+
+ g_assert (g_strv_length (ret) == 1);
+ g_assert_cmpstr (ret[0], ==, input);
+}
+
+static void
+test_pipestr (void)
+{
+ gchar **ret;
+ GError *error = NULL;
+ gchar const *input = "Hello world";
+ gchar *cmdstr;
+ GitgCommand **commands;
+
+ cmdstr = g_strconcat ("echo '", input, "' | cat -", NULL);
+
+ commands = gitg_shell_parse_commands (NULL, cmdstr, &error);
+
+ g_assert_no_error (error);
+ g_assert (commands);
+
+ ret = gitg_shell_run_sync_with_output_list (commands,
+ FALSE,
+ &error);
+
+ g_assert_no_error (error);
+ g_assert (ret);
+
+ g_assert (g_strv_length (ret) == 1);
+ g_assert_cmpstr (ret[0], ==, input);
+}
+
+int
+main (int argc,
+ char *argv[])
+{
+ g_type_init ();
+ g_test_init (&argc, &argv, NULL);
+
+ gitg_debug_init ();
+
+ test_add_repo ("/shell/success", test_success);
+ test_add_repo ("/shell/fail", test_fail);
+
+ test_add_repo ("/shell/output", test_output);
+
+ g_test_add_func ("/shell/input", test_input);
+ g_test_add_func ("/shell/pipe", test_pipe);
+ g_test_add_func ("/shell/pipestr", test_pipestr);
+
+ return g_test_run ();
+}
+/* ex:ts=8:noet: */
diff --git a/tools/Makefile.am b/tools/Makefile.am
new file mode 100644
index 0000000..9c6e256
--- /dev/null
+++ b/tools/Makefile.am
@@ -0,0 +1,10 @@
+INCLUDES = -g -I$(top_srcdir) -I$(top_srcdir)/gitg -I$(top_srcdir)/libgitg $(GITG_DEBUG_FLAGS) $(GITG_CFLAGS)
+
+noinst_PROGRAMS = $(TOOLS_PROGS)
+tools_ldadd = $(top_builddir)/libgitg/libgitg-1.0.la
+
+TOOLS_PROGS = gitg-shell
+gitg_shell_SOURCES = gitg-shell.c
+gitg_shell_LDADD = $(tools_ldadd)
+
+-include $(top_srcdir)/git.mk
diff --git a/tools/gitg-shell.c b/tools/gitg-shell.c
new file mode 100644
index 0000000..16ae312
--- /dev/null
+++ b/tools/gitg-shell.c
@@ -0,0 +1,206 @@
+#include <glib.h>
+#include <stdlib.h>
+#include <libgitg/gitg-shell.h>
+#include <gio/gunixinputstream.h>
+#include <gio/gunixoutputstream.h>
+#include <libgitg/gitg-debug.h>
+
+static gchar *repository_path = NULL;
+
+static GOptionEntry entries[] =
+{
+ { "repository", 'r', 0, G_OPTION_ARG_FILENAME, &repository_path, "Repository path" },
+ { NULL }
+};
+
+static GFile *
+find_git_dir (GFile *work_tree)
+{
+ GFile *ret;
+
+ work_tree = g_file_dup (work_tree);
+
+ while (work_tree)
+ {
+ ret = g_file_get_child (work_tree, ".git");
+
+ if (g_file_query_exists (ret, NULL))
+ {
+ g_object_unref (work_tree);
+ return ret;
+ }
+ else
+ {
+ GFile *tmp;
+
+ tmp = g_file_get_parent (work_tree);
+ g_object_unref (work_tree);
+
+ work_tree = tmp;
+ }
+ }
+
+ return NULL;
+}
+
+static void
+parse_options (int *argc,
+ char ***argv)
+{
+ GError *error = NULL;
+ GOptionContext *context;
+
+ context = g_option_context_new ("- git shell tool");
+
+ g_option_context_set_ignore_unknown_options (context, TRUE);
+ g_option_context_add_main_entries (context, entries, "gitg");
+
+ if (!g_option_context_parse (context, argc, argv, &error))
+ {
+ g_print ("option parsing failed: %s\n", error->message);
+ g_error_free (error);
+
+ exit (1);
+ }
+
+ g_option_context_free (context);
+}
+
+static void
+on_shell_end (GitgShell *shell,
+ GError *error,
+ GMainLoop *loop)
+{
+ g_main_loop_quit (loop);
+}
+
+int
+main (int argc, char *argv[])
+{
+ GitgRepository *repository;
+ GFile *work_tree;
+ GFile *git_dir;
+ gint i;
+ GString *cmdstr;
+ gchar *cs;
+ GitgCommand **commands;
+ GitgShell *shell;
+ GMainLoop *loop;
+ GError *error = NULL;
+ GInputStream *input;
+ GOutputStream *output;
+
+ g_type_init ();
+
+ parse_options (&argc, &argv);
+
+ gitg_debug_init ();
+
+ if (i == 1)
+ {
+ g_print ("Please specify a command...\n");
+ return 1;
+ }
+
+ if (!repository_path)
+ {
+ gchar *path;
+ GFile *file;
+
+ path = g_get_current_dir ();
+ file = g_file_new_for_path (path);
+
+ git_dir = find_git_dir (file);
+ g_free (path);
+ g_object_unref (file);
+
+ if (git_dir)
+ {
+ work_tree = g_file_get_parent (git_dir);
+ }
+ }
+ else
+ {
+ work_tree = g_file_new_for_commandline_arg (repository_path);
+ git_dir = find_git_dir (work_tree);
+ }
+
+ if (!git_dir)
+ {
+ g_print ("Could not find git dir...\n");
+ return 1;
+ }
+
+ repository = gitg_repository_new (git_dir, work_tree);
+
+ g_object_unref (work_tree);
+ g_object_unref (git_dir);
+
+ cmdstr = g_string_new ("");
+
+ /* Create commands */
+ for (i = 1; i < argc; ++i)
+ {
+ gchar *quoted;
+
+ if (strcmp (argv[i], "!") == 0)
+ {
+ quoted = g_strdup ("|");
+ }
+ else
+ {
+ quoted = g_shell_quote (argv[i]);
+ }
+
+ if (i != 1)
+ {
+ g_string_append_c (cmdstr, ' ');
+ }
+
+ g_string_append (cmdstr, quoted);
+ }
+
+ cs = g_string_free (cmdstr, FALSE);
+ g_print ("Running: %s\n\n", cs);
+
+ commands = gitg_shell_parse_commands (repository, cs, &error);
+
+ g_free (cs);
+ g_object_unref (repository);
+
+ if (error)
+ {
+ g_print ("Could not parse arguments: %s\n", error->message);
+ g_error_free (error);
+
+ return 1;
+ }
+
+ loop = g_main_loop_new (NULL, FALSE);
+ shell = gitg_shell_new (1000);
+
+ input = g_unix_input_stream_new (STDIN_FILENO, TRUE);
+ output = g_unix_output_stream_new (STDOUT_FILENO, TRUE);
+
+ gitg_io_set_input (GITG_IO (shell), input);
+ gitg_io_set_output (GITG_IO (shell), output);
+
+ g_signal_connect (shell,
+ "end",
+ G_CALLBACK (on_shell_end),
+ loop);
+
+ if (!gitg_shell_run_list (shell, commands, &error))
+ {
+ g_print ("Error launching shell: %s\n", error->message);
+ return 1;
+ }
+
+ g_free (commands);
+
+ g_main_loop_run (loop);
+ g_main_loop_unref (loop);
+ g_object_unref (shell);
+
+ return 0;
+}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]