Implement bisecting
[anjuta-git-plugin.git] / plugins / git / git-ref-command.c
blob3b5befc8050930dbaf61461bc538d8a2d9fb9de8
1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
2 /*
3 * anjuta
4 * Copyright (C) James Liggett 2008 <jrliggett@cox.net>
5 *
6 * anjuta is free software.
7 *
8 * You may redistribute it and/or modify it under the terms of the
9 * GNU General Public License, as published by the Free Software
10 * Foundation; either version 2 of the License, or (at your option)
11 * any later version.
13 * anjuta is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16 * See the GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with anjuta. If not, write to:
20 * The Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor
22 * Boston, MA 02110-1301, USA.
25 #include "git-ref-command.h"
27 #define BRANCH_REF_REGEX "([[:xdigit:]]{40}) refs/heads/(.*)"
28 #define TAG_REF_REGEX "([[:xdigit:]]{40}) refs/tags/(.*)"
29 #define REMOTE_REF_REGEX "([[:xdigit:]]{40}) refs/remotes/(.*)"
31 struct _GitRefCommandPriv
33 GRegex *branch_ref_regex;
34 GRegex *tag_ref_regex;
35 GRegex *remote_ref_regex;
36 GHashTable *refs;
39 G_DEFINE_TYPE (GitRefCommand, git_ref_command, GIT_TYPE_COMMAND);
41 static void
42 free_refs_list (GList *refs)
44 GList *current_ref;
46 current_ref = refs;
48 while (current_ref)
50 g_object_unref (current_ref->data);
51 current_ref = g_list_next (current_ref);
54 g_list_free (refs);
57 static void
58 git_ref_command_init (GitRefCommand *self)
60 self->priv = g_new0 (GitRefCommandPriv, 1);
62 self->priv->branch_ref_regex = g_regex_new (BRANCH_REF_REGEX, 0, 0, NULL);
63 self->priv->tag_ref_regex = g_regex_new (TAG_REF_REGEX, 0, 0, NULL);
64 self->priv->remote_ref_regex = g_regex_new (REMOTE_REF_REGEX, 0, 0, NULL);
65 self->priv->refs = g_hash_table_new_full (g_str_hash, g_str_equal,
66 NULL,
67 (GDestroyNotify) free_refs_list);
70 static void
71 git_ref_command_finalize (GObject *object)
73 GitRefCommand *self;
75 self = GIT_REF_COMMAND (object);
77 g_regex_unref (self->priv->branch_ref_regex);
78 g_regex_unref (self->priv->tag_ref_regex);
79 g_regex_unref (self->priv->remote_ref_regex);
80 g_hash_table_unref (self->priv->refs);
82 g_free (self->priv);
84 G_OBJECT_CLASS (git_ref_command_parent_class)->finalize (object);
87 static guint
88 git_ref_command_run (AnjutaCommand *command)
90 git_command_add_arg (GIT_COMMAND (command), "show-ref");
91 git_command_add_arg (GIT_COMMAND (command), "--dereference");
93 return 0;
96 static void
97 git_ref_command_insert_ref (GitRefCommand *self, const gchar *sha, GitRef *ref)
99 GList *ref_list;
100 gchar *name;
101 gchar *old_sha;
103 name = git_ref_get_name (ref);
105 ref_list = g_hash_table_lookup (self->priv->refs, sha);
107 ref_list = g_list_append (ref_list, ref);
109 if (g_hash_table_lookup_extended (self->priv->refs, sha,
110 (gpointer) &old_sha, NULL))
112 /* Change the list head for this SHA without destroying it */
113 g_hash_table_steal (self->priv->refs, sha);
115 g_free (old_sha);
118 g_hash_table_insert (self->priv->refs, g_strdup (sha), ref_list);
120 g_free (name);
123 static void
124 git_ref_command_handle_output (GitCommand *git_command, const gchar *output)
126 GitRefCommand *self;
127 GMatchInfo *match_info;
128 gchar *sha;
129 gchar *name;
130 GitRef *ref;
132 self = GIT_REF_COMMAND (git_command);
133 match_info = NULL;
135 if (g_regex_match (self->priv->branch_ref_regex, output, 0, &match_info))
137 sha = g_match_info_fetch (match_info, 1);
138 name = g_match_info_fetch (match_info, 2);
139 ref = git_ref_new (name, GIT_REF_TYPE_BRANCH);
141 git_ref_command_insert_ref (self, sha, ref);
143 g_free (sha);
144 g_free (name);
146 else if (g_regex_match (self->priv->tag_ref_regex, output, 0, &match_info))
148 sha = g_match_info_fetch (match_info, 1);
149 name = g_match_info_fetch (match_info, 2);
151 if (g_str_has_suffix (name, "^{}"))
152 (g_strrstr (name, "^{}")) [0] = '\0';
154 ref = git_ref_new (name, GIT_REF_TYPE_TAG);
157 git_ref_command_insert_ref (self, sha, ref);
159 g_free (sha);
160 g_free (name);
162 else if (g_regex_match (self->priv->remote_ref_regex, output, 0,
163 &match_info))
165 sha = g_match_info_fetch (match_info, 1);
166 name = g_match_info_fetch (match_info, 2);
167 ref = git_ref_new (name, GIT_REF_TYPE_REMOTE);
169 git_ref_command_insert_ref (self, sha, ref);
171 g_free (sha);
172 g_free (name);
175 if (match_info)
176 g_match_info_free (match_info);
179 static void
180 git_ref_command_class_init (GitRefCommandClass *klass)
182 GObjectClass* object_class = G_OBJECT_CLASS (klass);
183 GitCommandClass* parent_class = GIT_COMMAND_CLASS (klass);
184 AnjutaCommandClass *command_class = ANJUTA_COMMAND_CLASS (klass);
186 object_class->finalize = git_ref_command_finalize;
187 parent_class->output_handler = git_ref_command_handle_output;
188 command_class->run = git_ref_command_run;
192 GitRefCommand *
193 git_ref_command_new (const gchar *working_directory)
195 return g_object_new (GIT_TYPE_REF_COMMAND,
196 "working-directory", working_directory,
197 "single-line-output", TRUE,
198 NULL);
201 GHashTable *
202 git_ref_command_get_refs (GitRefCommand *self)
204 return g_hash_table_ref (self->priv->refs);