[gitg] Use remote pushes for push branch menu



commit 19beb8e56951d3398b2b2d1fffc1bcadb2140f12
Author: Edward Rudd <urkle outoforder cc>
Date:   Tue Jan 12 17:54:17 2010 -0500

    Use remote pushes for push branch menu
    
    https://bugzilla.gnome.org/show_bug.cgi?id=606792

 gitg/gitg-repository.c |  135 ++++++++++++++++++++++++++++++++++++++++++++----
 gitg/gitg-repository.h |    1 +
 gitg/gitg-window.c     |  131 +++++++++++++++++++++++++++++------------------
 3 files changed, 206 insertions(+), 61 deletions(-)
---
diff --git a/gitg/gitg-repository.c b/gitg/gitg-repository.c
index 402e281..9a64031 100644
--- a/gitg/gitg-repository.c
+++ b/gitg/gitg-repository.c
@@ -91,6 +91,9 @@ struct _GitgRepositoryPrivate
 	gint stamp;
 	GType column_types[N_COLUMNS];
 
+	GHashTable *ref_pushes;
+	GHashTable *ref_names;
+
 	GitgRevision **storage;
 	GitgLanes *lanes;
 	GHashTable *refs;
@@ -346,10 +349,12 @@ do_clear(GitgRepository *repository, gboolean emit)
 	repository->priv->current_ref = NULL;
 
 	/* clear hash tables */
-	g_hash_table_remove_all(repository->priv->hashtable);
-	g_hash_table_remove_all(repository->priv->refs);
+	g_hash_table_remove_all (repository->priv->hashtable);
+	g_hash_table_remove_all (repository->priv->refs);
+	g_hash_table_remove_all (repository->priv->ref_names);
+	g_hash_table_remove_all (repository->priv->ref_pushes);
 
-	gitg_color_reset();
+	gitg_color_reset ();
 }
 
 static void
@@ -377,8 +382,10 @@ gitg_repository_finalize(GObject *object)
 	}
 
 	/* Free the hash */
-	g_hash_table_destroy(rp->priv->hashtable);
-	g_hash_table_destroy(rp->priv->refs);
+	g_hash_table_destroy (rp->priv->hashtable);
+	g_hash_table_destroy (rp->priv->refs);
+	g_hash_table_destroy (rp->priv->ref_names);
+	g_hash_table_destroy (rp->priv->ref_pushes);
 
 	/* Free cached args */
 	g_strfreev(rp->priv->last_args);
@@ -734,11 +741,15 @@ find_ref_custom (GitgRef *first, GitgRef *second)
 }
 
 static GitgRef *
-add_ref(GitgRepository *self, gchar const *sha1, gchar const *name)
+add_ref (GitgRepository *self, gchar const *sha1, gchar const *name)
 {
-	GitgRef *ref = gitg_ref_new(sha1, name);
-	GSList *refs = (GSList *)g_hash_table_lookup(self->priv->refs, 
-	                                             gitg_ref_get_hash(ref));
+	GitgRef *ref = gitg_ref_new (sha1, name);
+	GSList *refs = (GSList *)g_hash_table_lookup (self->priv->refs,
+	                                              gitg_ref_get_hash (ref));
+
+	g_hash_table_insert (self->priv->ref_names,
+	                     (gpointer)gitg_ref_get_name (ref),
+	                     ref);
 
 	if (refs == NULL)
 	{
@@ -1098,8 +1109,15 @@ initialize_bindings(GitgRepository *repository)
 static void
 gitg_repository_init(GitgRepository *object)
 {
-	object->priv = GITG_REPOSITORY_GET_PRIVATE(object);
-	object->priv->hashtable = g_hash_table_new_full(gitg_utils_hash_hash, gitg_utils_hash_equal, NULL, NULL);
+	object->priv = GITG_REPOSITORY_GET_PRIVATE (object);
+
+	object->priv->hashtable = g_hash_table_new (gitg_utils_hash_hash,
+	                                            gitg_utils_hash_equal);
+
+	object->priv->ref_pushes = g_hash_table_new (gitg_utils_hash_hash,
+	                                             gitg_utils_hash_equal);
+
+	object->priv->ref_names = g_hash_table_new (g_str_hash, g_str_equal);
 
 	object->priv->column_types[0] = GITG_TYPE_REVISION;
 	object->priv->column_types[1] = G_TYPE_STRING;
@@ -1749,6 +1767,101 @@ gitg_repository_get_remotes (GitgRepository *repository)
 	return (gchar **)g_ptr_array_free (remotes, FALSE);
 }
 
+GSList const *
+gitg_repository_get_ref_pushes (GitgRepository *repository, GitgRef *ref)
+{
+	gpointer ret;
+	GitgRef *my_ref;
+
+	g_return_val_if_fail (GITG_IS_REPOSITORY (repository), NULL);
+
+	my_ref = g_hash_table_lookup (repository->priv->ref_names,
+	                              gitg_ref_get_name (ref));
+
+	if (!my_ref)
+	{
+		return NULL;
+	}
+
+	if (g_hash_table_lookup_extended (repository->priv->ref_pushes,
+	                                  my_ref,
+	                                  NULL,
+	                                  &ret))
+	{
+		return ret;
+	}
+
+	GitgConfig *config = gitg_config_new (repository);
+	gchar *escaped = g_regex_escape_string (gitg_ref_get_name (my_ref), -1);
+	gchar *value_regex = g_strdup_printf ("^%s:", escaped);
+
+	gchar *pushes = gitg_config_get_value_regex (config,
+	                                          "remote\\..*\\.push",
+	                                          value_regex);
+
+	g_free (escaped);
+	g_free (value_regex);
+
+	if (!pushes || !*pushes)
+	{
+		g_object_unref (config);
+		g_free (pushes);
+
+		g_hash_table_insert (repository->priv->ref_pushes,
+		                     my_ref,
+		                     NULL);
+
+		return NULL;
+	}
+
+	gchar **lines = g_strsplit (pushes, "\n", -1);
+	gchar **ptr = lines;
+
+	g_free (pushes);
+
+	GRegex *regex = g_regex_new ("remote\\.(.+?)\\.push\\s+.*:refs/heads/(.*)", 0, 0, NULL);
+	GSList *refs = NULL;
+
+	while (*ptr)
+	{
+		GMatchInfo *info = NULL;
+
+		if (g_regex_match (regex, *ptr, 0, &info))
+		{
+			gchar *remote = g_match_info_fetch (info, 1);
+			gchar *branch = g_match_info_fetch (info, 2);
+
+			gchar *rr = g_strconcat ("refs/remotes/", remote, "/", branch, NULL);
+
+			GitgRef *remref = g_hash_table_lookup (repository->priv->ref_names,
+			                                       rr);
+
+			g_free (rr);
+			g_free (remote);
+			g_free (branch);
+
+			if (remref)
+			{
+				refs = g_slist_prepend (refs, remref);
+			}
+		}
+
+		g_match_info_free (info);
+		++ptr;
+	}
+
+	g_object_unref (config);
+	g_strfreev (lines);
+
+	refs = g_slist_reverse (refs);
+
+	g_hash_table_insert (repository->priv->ref_pushes,
+	                     my_ref,
+	                     refs);
+
+	return refs;
+}
+
 gboolean
 gitg_repository_get_loaded (GitgRepository *repository)
 {
diff --git a/gitg/gitg-repository.h b/gitg/gitg-repository.h
index a678b61..a631742 100644
--- a/gitg/gitg-repository.h
+++ b/gitg/gitg-repository.h
@@ -118,6 +118,7 @@ gchar *gitg_repository_parse_head(GitgRepository *repository);
 void gitg_repository_reload(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);
 
 G_END_DECLS
diff --git a/gitg/gitg-window.c b/gitg/gitg-window.c
index 2b9a963..006a366 100644
--- a/gitg/gitg-window.c
+++ b/gitg/gitg-window.c
@@ -1954,16 +1954,64 @@ get_tracked_ref (GitgWindow *window, GitgRef *branch, gchar **retremote, gchar *
 	{
 		*retbranch = g_strdup (merge + 11);
 	}
+	else
+	{
+		*retbranch = NULL;
+	}
 
 	g_free (merge);
 }
 
+static gboolean
+repository_has_ref (GitgWindow *window, gchar const *remote, gchar const *branch)
+{
+	GSList *refs = gitg_repository_get_refs (window->priv->repository);
+	gchar *combined = g_strconcat (remote, "/", branch, NULL);
+
+	while (refs)
+	{
+		GitgRef *r = (GitgRef *)refs->data;
+
+		if (gitg_ref_get_ref_type (r) == GITG_REF_TYPE_REMOTE &&
+		    strcmp (gitg_ref_get_shortname (r), combined) == 0)
+		{
+			g_free (combined);
+			return TRUE;
+		}
+
+		refs = g_slist_next (refs);
+	}
+
+	g_free (combined);
+	return FALSE;
+}
+
 static void
-add_push_action (GitgWindow *window, GtkActionGroup *group, gchar const *name, gchar const *remote, gchar const *branch)
+add_push_action (GitgWindow *window,
+                 GtkActionGroup *group,
+                 gchar const *remote,
+                 gchar const *branch)
 {
 	gchar *acname = g_strconcat ("Push", remote, branch, "Action", NULL);
-	GtkAction *pushac = gtk_action_new (acname, name, NULL, NULL);
+	gchar *name;
+
+	if (gtk_action_group_get_action (group, acname) != NULL)
+	{
+		/* No need for twice the same */
+		g_free (acname);
+		return;
+	}
+
+	if (repository_has_ref (window, remote, branch))
+	{
+		name = g_strconcat (remote, "/", branch, NULL);
+	}
+	else
+	{
+		name = g_strconcat (remote, "/", branch, " (", _("new"), ")", NULL);
+	}
 
+	GtkAction *pushac = gtk_action_new (acname, name, NULL, NULL);
 	gtk_action_group_add_action (group, pushac);
 
 	gchar *nm = g_strconcat ("Push", remote, branch, NULL);
@@ -1989,30 +2037,10 @@ add_push_action (GitgWindow *window, GtkActionGroup *group, gchar const *name, g
 		              "activate",
 		              G_CALLBACK (on_push_activated),
 		              window);
-}
 
-static gboolean
-repository_has_ref (GitgWindow *window, gchar const *remote, GitgRef *ref)
-{
-	GSList *refs = gitg_repository_get_refs (window->priv->repository);
-	gchar *combined = g_strconcat (remote, "/", gitg_ref_get_shortname (ref), NULL);
-
-	while (refs)
-	{
-		GitgRef *r = (GitgRef *)refs->data;
-
-		if (gitg_ref_get_ref_type (r) == GITG_REF_TYPE_REMOTE &&
-		    strcmp (gitg_ref_get_shortname (r), combined) == 0)
-		{
-			g_free (combined);
-			return TRUE;
-		}
-
-		refs = g_slist_next (refs);
-	}
-
-	g_free (combined);
-	return FALSE;
+	g_free (acname);
+	g_free (name);
+	g_free (nm);
 }
 
 static void
@@ -2169,47 +2197,50 @@ update_merge_rebase (GitgWindow *window, GitgRef *ref)
 		/* Get the tracked remote of this ref (if any) */
 		gchar *remote = NULL;
 		gchar *branch = NULL;
-		gchar *tracked = NULL;
-
-		gchar **remotes = gitg_repository_get_remotes (window->priv->repository);
-		gchar **ptr = remotes;
 
 		get_tracked_ref (window, ref, &remote, &branch);
 
 		if (remote)
 		{
-			tracked = g_strconcat (remote, "/", branch, NULL);
-			add_push_action (window, ac, tracked, remote, branch);
+			add_push_action (window,
+			                 ac,
+			                 remote,
+			                 branch ? branch : gitg_ref_get_shortname (ref));
+
+			g_free (remote);
+			g_free (branch);
 		}
 
-		while (*ptr)
+		GSList const *ref_pushes = gitg_repository_get_ref_pushes (window->priv->repository,
+		                                                           ref);
+
+		/* Get configured ref pushes */
+		while (ref_pushes)
 		{
-			if (!tracked || !g_str_has_prefix (tracked, *ptr))
-			{
-				gchar *name;
+			GitgRef *push_ref = ref_pushes->data;
 
-				if (repository_has_ref (window, *ptr, ref))
-				{
-					name = g_strconcat (*ptr, "/", gitg_ref_get_shortname (ref), NULL);
-				}
-				else
-				{
-					name = g_strconcat (*ptr, "/", gitg_ref_get_shortname (ref), " (", _("new"), ")", NULL);
-				}
+			add_push_action (window,
+			                 ac,
+			                 gitg_ref_get_prefix (push_ref),
+			                 gitg_ref_get_local_name (push_ref));
 
-				add_push_action (window, ac, name, *ptr, gitg_ref_get_shortname (ref));
+			ref_pushes = g_slist_next (ref_pushes);
+		}
 
-				g_free (name);
-			}
+		gchar **remotes = gitg_repository_get_remotes (window->priv->repository);
+		gchar **ptr = remotes;
+
+		while (*ptr)
+		{
+			add_push_action (window,
+			                 ac,
+			                 *ptr,
+			                 gitg_ref_get_shortname (ref));
 
 			++ptr;
 		}
 
-		g_free (tracked);
 		g_strfreev (remotes);
-
-		g_free (remote);
-		g_free (branch);
 	}
 
 	gtk_ui_manager_ensure_update (window->priv->menus_ui_manager);



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]