[anjuta] git: Fix bgo 680401: Git plugin (Status) doesn't work with git version 1.7.10.4



commit 9ae59b43dffe7ff16c29f7430b5dc2907b4bd1be
Author: James Liggett <jrliggett cox net>
Date:   Wed Aug 22 19:25:48 2012 -0700

    git: Fix bgo 680401: Git plugin (Status) doesn't work with git version 1.7.10.4
    
    Use the --porcelain mode for the status command. The manpage says the format of
    porcelain status output should never change, so we should never have this
    problem again.

 plugins/git/git-status-command.c |  187 +++++++++++++++++++-------------------
 plugins/git/git-status.c         |   50 +----------
 plugins/git/git-status.h         |    3 +-
 plugins/git/git-vcs-interface.c  |   43 ++++-----
 4 files changed, 118 insertions(+), 165 deletions(-)
---
diff --git a/plugins/git/git-status-command.c b/plugins/git/git-status-command.c
index 60ca5da..53d6b76 100644
--- a/plugins/git/git-status-command.c
+++ b/plugins/git/git-status-command.c
@@ -24,24 +24,15 @@
 
 #include "git-status-command.h"
 
-#define STATUS_REGEX "(modified|new file|deleted|unmerged|both modified|both added|both deleted):   (.*)"
-#define UNTRACKED_FILES_REGEX "(?:#\\t)(.*)"
-#define SECTION_COMMIT_REGEX "Changes to be committed:"
-#define SECTION_NOT_UPDATED_REGEX "Changed but not updated:|Changes not staged for commit:"
-#define SECTION_UNTRACKED_REGEX "Untracked files:"
+#define STATUS_REGEX "((M|A|D|U|\\?|\\s){2}) (.*)"
 
 struct _GitStatusCommandPriv
 {
 	GQueue *status_queue;
-	GHashTable *path_lookup_table;
 	GitStatusSections sections;
-	GitStatusSections current_section;
-	GRegex *current_section_regex;
+	GHashTable *status_codes;
+	GHashTable *conflict_codes;
 	GRegex *status_regex;
-	GRegex *untracked_files_regex;
-	GRegex *section_commit_regex;
-	GRegex *section_not_updated_regex;
-	GRegex *section_untracked_regex;
 	GFileMonitor *head_monitor;
 	GFileMonitor *index_monitor;
 };
@@ -52,6 +43,7 @@ static guint
 git_status_command_run (AnjutaCommand *command)
 {
 	git_command_add_arg (GIT_COMMAND (command), "status");
+	git_command_add_arg (GIT_COMMAND (command), "--porcelain");
 	
 	return 0;
 }
@@ -66,66 +58,82 @@ git_status_command_handle_output (GitCommand *git_command, const gchar *output)
 	gchar *path;
 	
 	self = GIT_STATUS_COMMAND (git_command);
-	
-	/* See if the section has changed */
-	if (g_regex_match (self->priv->section_commit_regex, output, 0, NULL))
-	{
-		self->priv->current_section = GIT_STATUS_SECTION_COMMIT;
-		self->priv->current_section_regex = self->priv->status_regex;
-		return;
-	}
-	else if (g_regex_match (self->priv->section_not_updated_regex, output, 0, 
-							NULL))
-	{
-		self->priv->current_section = GIT_STATUS_SECTION_NOT_UPDATED;
-		self->priv->current_section_regex = self->priv->status_regex;
-		return;
-	}
-	else if (g_regex_match (self->priv->section_untracked_regex, output, 0, 
-							NULL))
-	{
-		self->priv->current_section = GIT_STATUS_SECTION_UNTRACKED;
-		self->priv->current_section_regex = self->priv->untracked_files_regex;
-		return;
-	}
-	
-	if (self->priv->sections & self->priv->current_section)
+	status_object = NULL;
+
+	if (g_regex_match (self->priv->status_regex, output, 0, &match_info))
 	{
-		if (g_regex_match (self->priv->current_section_regex, output, 0, 
-						   &match_info))
+		/* Determine which section this entry goes in */
+		status = g_match_info_fetch (match_info, 1);
+		path = g_match_info_fetch (match_info, 3);
+
+		if (status[0] == ' ')
 		{
-			if (self->priv->current_section_regex == self->priv->status_regex)
+			/* Changed but not updated */
+			if (self->priv->sections & GIT_STATUS_SECTION_NOT_UPDATED)
 			{
-				status = g_match_info_fetch (match_info, 1);
-				path = g_match_info_fetch (match_info, 2);
+				status_object = git_status_new(path, 
+				                               GPOINTER_TO_INT (g_hash_table_lookup (self->priv->status_codes, 
+				                                                					 GINT_TO_POINTER (status[1]))));
 			}
-			else
+		}
+		else if (status[1] == ' ')
+		{
+			/* Added to commit */
+			if (self->priv->sections & GIT_STATUS_SECTION_COMMIT)
+			{
+				status_object = git_status_new(path, 
+				                               GPOINTER_TO_INT (g_hash_table_lookup (self->priv->status_codes, 
+				                                                    				 GINT_TO_POINTER (status[0]))));
+			}
+		}
+		else
+		{
+			/* File may have been added to the index and then changed again in
+			 * the working tree, or it could be a conflict */
+
+			/* Unversioned files */
+			if (status[0] == '?')
 			{
-				status = g_strdup ("untracked");
-				path = g_match_info_fetch (match_info, 1);
+				if (self->priv->sections & GIT_STATUS_SECTION_UNTRACKED)
+				{
+					status_object = git_status_new(path, 
+				                           		   ANJUTA_VCS_STATUS_UNVERSIONED);
+				}
 			}
-			
-			/* Git sometimes mentions paths twice in status output. This can
-			 * happen, for example, where there is a conflict, in which case a
-			 * path would show up as both "unmerged" and "modified." */
-			g_strchug (path);
-			
-			if (!g_hash_table_lookup_extended (self->priv->path_lookup_table, 
-											   path, NULL, NULL))
+			else if (g_hash_table_lookup_extended (self->priv->conflict_codes, status,
+			                                       NULL, NULL))
 			{
-				status_object = git_status_new (path, status);
-				g_queue_push_tail (self->priv->status_queue, status_object);
-				g_hash_table_insert (self->priv->path_lookup_table,  
-									 g_strdup (path), NULL);
-				anjuta_command_notify_data_arrived (ANJUTA_COMMAND (git_command));
+				/* Conflicts are put in the changed but not updated section */
+				if (self->priv->sections & GIT_STATUS_SECTION_NOT_UPDATED)
+				{
+					status_object = git_status_new (path, 
+					                                ANJUTA_VCS_STATUS_CONFLICTED);
+				}
 			}
-			
-			g_free (status);
-			g_free (path);
+			else
+			{
+				status_object = git_status_new(path, 
+				                               GPOINTER_TO_INT(g_hash_table_lookup (self->priv->status_codes, 
+				                                                                    GINT_TO_POINTER (status[0]))));
+			}
+			    
 		}
 
-		g_match_info_free (match_info);
+		
+
+		g_free (status);
+		g_free (path);
+
+		if (status_object)
+		{
+			g_queue_push_tail (self->priv->status_queue, status_object);
+			anjuta_command_notify_data_arrived (ANJUTA_COMMAND (self));
+		}
+		
 	}
+
+	g_match_info_free (match_info);
+	
 }
 
 static void
@@ -133,18 +141,33 @@ git_status_command_init (GitStatusCommand *self)
 {
 	self->priv = g_new0 (GitStatusCommandPriv, 1);
 	self->priv->status_queue = g_queue_new ();
-	self->priv->path_lookup_table = g_hash_table_new_full (g_str_hash, 
-														   g_str_equal,
-														   g_free, NULL);
+	
 	self->priv->status_regex = g_regex_new (STATUS_REGEX, 0, 0, NULL);
-	self->priv->untracked_files_regex = g_regex_new (UNTRACKED_FILES_REGEX, 
-													 0, 0, NULL);
-	self->priv->section_commit_regex = g_regex_new (SECTION_COMMIT_REGEX, 0, 0,
-													NULL);
-	self->priv->section_not_updated_regex = g_regex_new (SECTION_NOT_UPDATED_REGEX,
-														 0, 0, NULL);
-	self->priv->section_untracked_regex = g_regex_new (SECTION_UNTRACKED_REGEX,
-													   0, 0, NULL);
+	self->priv->status_codes = g_hash_table_new (g_direct_hash, g_direct_equal);
+	self->priv->conflict_codes = g_hash_table_new (g_str_hash, g_str_equal);
+
+	/* Initialize status code hash tables */
+	g_hash_table_insert (self->priv->status_codes, 
+	                     GINT_TO_POINTER ('M'),
+	                     GINT_TO_POINTER (ANJUTA_VCS_STATUS_MODIFIED));
+
+	g_hash_table_insert (self->priv->status_codes, 
+	                     GINT_TO_POINTER ('A'),
+	                     GINT_TO_POINTER (ANJUTA_VCS_STATUS_ADDED));
+
+	g_hash_table_insert (self->priv->status_codes, 
+	                     GINT_TO_POINTER ('D'),
+	                     GINT_TO_POINTER (ANJUTA_VCS_STATUS_MODIFIED));
+
+	/* TODO: Handle each conflict case individually so that we can eventually
+	 * give the user more information about the conflict */
+	g_hash_table_insert (self->priv->conflict_codes, "DD", NULL);
+	g_hash_table_insert (self->priv->conflict_codes, "AU", NULL);
+	g_hash_table_insert (self->priv->conflict_codes, "UD", NULL);
+	g_hash_table_insert (self->priv->conflict_codes, "UA", NULL);
+	g_hash_table_insert (self->priv->conflict_codes, "DU", NULL);
+	g_hash_table_insert (self->priv->conflict_codes, "AA", NULL);
+	g_hash_table_insert (self->priv->conflict_codes, "UU", NULL);
 }
 
 static void
@@ -253,38 +276,19 @@ git_status_command_data_arrived (AnjutaCommand *command)
 	git_status_command_clear_output (GIT_STATUS_COMMAND (command));
 }
 
-static void
-git_status_command_finished (AnjutaCommand *command, guint return_code)
-{
-	GitStatusCommand *self;
-
-	self = GIT_STATUS_COMMAND (command);
-
-	g_hash_table_remove_all (self->priv->path_lookup_table);
-
-	ANJUTA_COMMAND_CLASS (git_status_command_parent_class)->command_finished (command, 
-	                                                                          return_code);
-}
 
 static void
 git_status_command_finalize (GObject *object)
 {
 	GitStatusCommand *self;
-	GList *current_status;
 	
 	self = GIT_STATUS_COMMAND (object);
-	current_status = self->priv->status_queue->head;
 	
 	git_status_command_clear_output (self);
 	git_status_command_stop_automatic_monitor (ANJUTA_COMMAND (self));
 	
 	g_queue_free (self->priv->status_queue);
-	g_hash_table_destroy (self->priv->path_lookup_table);
 	g_regex_unref (self->priv->status_regex);
-	g_regex_unref (self->priv->untracked_files_regex);
-	g_regex_unref (self->priv->section_commit_regex);
-	g_regex_unref (self->priv->section_not_updated_regex);
-	g_regex_unref (self->priv->section_untracked_regex);
 	
 	g_free (self->priv);
 
@@ -302,7 +306,6 @@ git_status_command_class_init (GitStatusCommandClass *klass)
 	parent_class->output_handler = git_status_command_handle_output;
 	command_class->run = git_status_command_run;
 	command_class->data_arrived = git_status_command_data_arrived;
-	command_class->command_finished = git_status_command_finished;
 	command_class->start_automatic_monitor = git_status_command_start_automatic_monitor;
 	command_class->stop_automatic_monitor = git_status_command_stop_automatic_monitor;
 }
diff --git a/plugins/git/git-status.c b/plugins/git/git-status.c
index c6766cb..5f2307a 100644
--- a/plugins/git/git-status.c
+++ b/plugins/git/git-status.c
@@ -27,7 +27,6 @@
 struct _GitStatusPriv
 {
 	gchar *path;
-	GHashTable *status_lookup_table;
 	AnjutaVcsStatus status;
 };
 
@@ -37,43 +36,6 @@ static void
 git_status_init (GitStatus *self)
 {
 	self->priv = g_new0 (GitStatusPriv, 1);
-	self->priv->status_lookup_table = g_hash_table_new (g_str_hash, 
-														g_str_equal);
-	
-	/* Set up mappings between git status and VCS status codes */
-	g_hash_table_insert (self->priv->status_lookup_table,
-						 "modified", 
-						 GINT_TO_POINTER (ANJUTA_VCS_STATUS_MODIFIED));
-	
-	g_hash_table_insert (self->priv->status_lookup_table,
-						 "new file", 
-						 GINT_TO_POINTER (ANJUTA_VCS_STATUS_ADDED));
-	
-	g_hash_table_insert (self->priv->status_lookup_table,
-						 "deleted", 
-						 GINT_TO_POINTER (ANJUTA_VCS_STATUS_DELETED));
-	
-	/* Git 1.7 added a bunch of different conflicted states */
-
-	g_hash_table_insert (self->priv->status_lookup_table,
-						 "unmerged", 
-						 GINT_TO_POINTER (ANJUTA_VCS_STATUS_CONFLICTED));
-
-	g_hash_table_insert (self->priv->status_lookup_table,
-						 "both modified", 
-						 GINT_TO_POINTER (ANJUTA_VCS_STATUS_CONFLICTED));
-
-	g_hash_table_insert (self->priv->status_lookup_table,
-						 "both added", 
-						 GINT_TO_POINTER (ANJUTA_VCS_STATUS_CONFLICTED));
-
-	g_hash_table_insert (self->priv->status_lookup_table,
-						 "both deleted", 
-						 GINT_TO_POINTER (ANJUTA_VCS_STATUS_CONFLICTED));
-	
-	g_hash_table_insert (self->priv->status_lookup_table,
-						 "untracked", 
-						 GINT_TO_POINTER (ANJUTA_VCS_STATUS_UNVERSIONED));
 }
 
 static void
@@ -84,7 +46,6 @@ git_status_finalize (GObject *object)
 	self = GIT_STATUS (object);
 	
 	g_free (self->priv->path);
-	g_hash_table_destroy (self->priv->status_lookup_table);
 	g_free (self->priv);
 
 	G_OBJECT_CLASS (git_status_parent_class)->finalize (object);
@@ -99,15 +60,14 @@ git_status_class_init (GitStatusClass *klass)
 }
 
 GitStatus *
-git_status_new (const gchar *path, const gchar *status)
+git_status_new (const gchar *path, AnjutaVcsStatus status)
 {
 	GitStatus *self;
 	
 	self = g_object_new (GIT_TYPE_STATUS, NULL);
 	
 	self->priv->path = g_strdup (path);
-	self->priv->status = GPOINTER_TO_INT (g_hash_table_lookup (self->priv->status_lookup_table,
-															   status));
+	self->priv->status = status;
 	
 	return self;
 }
@@ -124,9 +84,3 @@ git_status_get_vcs_status (GitStatus *self)
 	return self->priv->status;
 }
 
-gboolean
-git_status_is_working_directory_descendant (GitStatus *self)
-{
-	return (!g_str_has_prefix (self->priv->path, "../") && 
-			!g_str_has_prefix (self->priv->path, "./"));
-}
diff --git a/plugins/git/git-status.h b/plugins/git/git-status.h
index 88d0b5f..c931bdd 100644
--- a/plugins/git/git-status.h
+++ b/plugins/git/git-status.h
@@ -54,10 +54,9 @@ struct _GitStatus
 };
 
 GType git_status_get_type (void) G_GNUC_CONST;
-GitStatus *git_status_new (const gchar *path, const gchar *status);
+GitStatus *git_status_new (const gchar *path, AnjutaVcsStatus status);
 gchar *git_status_get_path (GitStatus *self);
 AnjutaVcsStatus git_status_get_vcs_status (GitStatus *self);
-gboolean git_status_is_working_directory_descendant (GitStatus *self);
 
 G_END_DECLS
 
diff --git a/plugins/git/git-vcs-interface.c b/plugins/git/git-vcs-interface.c
index 3620596..5f1eca5 100644
--- a/plugins/git/git-vcs-interface.c
+++ b/plugins/git/git-vcs-interface.c
@@ -192,6 +192,7 @@ on_status_command_data_arrived (AnjutaCommand *command,
 {
 	GQueue *status_queue;
 	GitStatus *status;
+	const gchar *working_directory;
 	gchar *path;
 	gchar *full_path;
 	GFile *file;
@@ -201,32 +202,29 @@ on_status_command_data_arrived (AnjutaCommand *command,
 	while (g_queue_peek_head (status_queue))
 	{
 		status = g_queue_pop_head (status_queue);
+		working_directory = g_object_get_data (G_OBJECT (command), 
+		                                       "working-directory");
+		path = git_status_get_path (status);
+		full_path = g_strconcat (working_directory, G_DIR_SEPARATOR_S, path, 
+		                         NULL);
+		file = g_file_new_for_path (full_path);
 
-		if (git_status_is_working_directory_descendant (status))
-		{
-			path = git_status_get_path (status);
-			full_path = g_strconcat (g_object_get_data (G_OBJECT (command), "working-directory"),
-			                         G_DIR_SEPARATOR_S, path, NULL);
-			file = g_file_new_for_path (full_path);
-
-			DEBUG_PRINT ("Working directory: %s\n", (gchar *) g_object_get_data (G_OBJECT (command), "working-directory"));
-			DEBUG_PRINT ("File %s Status %i\n", full_path, git_status_get_vcs_status (status));
-
-			if (file)
-			{
-				callback (file, 
-				          git_status_get_vcs_status (status),
-				          g_object_get_data (G_OBJECT (command), "user-data"));
+		DEBUG_PRINT ("Working directory: %s\n", working_directory);
+		DEBUG_PRINT ("File %s Status %i\n", full_path, git_status_get_vcs_status (status));
 
-				g_object_unref (file);
-			}
+		if (file)
+		{
+			callback (file, 
+			          git_status_get_vcs_status (status),
+			          g_object_get_data (G_OBJECT (command), "user-data"));
 
-			g_free (path);
-			g_free (full_path);
+			g_object_unref (file);
 		}
+
+		g_free (path);
+		g_free (full_path);
 		
 		g_object_unref (status);
-		
 	}
 }
 
@@ -245,9 +243,8 @@ git_ivcs_query_status (IAnjutaVcs *obj, GFile *file,
 	g_free (path);
 
 	g_object_set_data (G_OBJECT (status_command), "user-data", user_data);
-	g_object_set_data_full (G_OBJECT (status_command), "working-directory",
-	                        g_file_get_path (file),
-	                        (GDestroyNotify) g_free);
+	g_object_set_data (G_OBJECT (status_command), "working-directory",
+	                   ANJUTA_PLUGIN_GIT (obj)->project_root_directory);
 
 	g_signal_connect (G_OBJECT (status_command), "data-arrived",
 	                  G_CALLBACK (on_status_command_data_arrived),



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