You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by da...@apache.org on 2010/08/05 12:24:23 UTC

svn commit: r982534 - in /subversion/trunk/subversion: libsvn_diff/parse-diff.c tests/libsvn_diff/parse-diff-test.c

Author: dannas
Date: Thu Aug  5 10:24:23 2010
New Revision: 982534

URL: http://svn.apache.org/viewvc?rev=982534&view=rev
Log:
Make the diff parser able to handle paths with spaces in the 
"--git diff a/path b/path" line. At the same time start
recording path information from other header fields. 

We only need the filenames from the --git diff line if we're
dealing with added or deleted empty files. In those cases, the 
paths should be identical.

The git_start() function probably needs some adjusting but it passes
the tests so I'm committing it. :).

* subversion/libsvn_diff/parse-diff.c
  (git_start): First check that we have a header line on the form 
    "--git diff a/.+ b/.+". Then grab the old and new filename if
    they are the same.
  (git_minus,
   git_plus,
   git_move_from,
   git_move_to,
   git_copy_from,
   git_copy_to): Start grabbing filenames.

* subversion/tests/libsvn_diff/parse-diff-test.c
  (test_funcs): Remove XFail marker for test_git_diffs_with_spaces_diff.

Modified:
    subversion/trunk/subversion/libsvn_diff/parse-diff.c
    subversion/trunk/subversion/tests/libsvn_diff/parse-diff-test.c

Modified: subversion/trunk/subversion/libsvn_diff/parse-diff.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_diff/parse-diff.c?rev=982534&r1=982533&r2=982534&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_diff/parse-diff.c (original)
+++ subversion/trunk/subversion/libsvn_diff/parse-diff.c Thu Aug  5 10:24:23 2010
@@ -881,10 +881,12 @@ static svn_error_t *
 git_start(enum parse_state *new_state, const char *line, svn_patch_t *patch,
           apr_pool_t *result_pool, apr_pool_t *scratch_pool)
 {
-  const char *old_path;
-  const char *new_path;
-  char *end_old_path;
-  char *slash;
+  const char *old_path_start;
+  char *old_path_end;
+  const char *new_path_start;
+  const char *new_path_end;
+  char *new_path_marker;
+  const char *old_path_marker;
 
   /* ### Add handling of escaped paths
    * http://www.kernel.org/pub/software/scm/git/docs/git-diff.html: 
@@ -897,59 +899,79 @@ git_start(enum parse_state *new_state, c
   /* Our line should look like this: 'git --diff a/path b/path'. 
    * If we find any deviations from that format, we return with state reset
    * to start.
-   *
-   * ### We can't handle paths with spaces!
    */
-  slash = strchr(line, '/');
+  old_path_marker = strstr(line, " a/");
 
-  if (! slash)
+  if (! old_path_marker)
     {
       *new_state = state_start;
       return SVN_NO_ERROR;
     }
 
-  old_path = slash + 1;
-
-  if (! *old_path)
+  if (! *(old_path_marker + 3))
     {
       *new_state = state_start;
       return SVN_NO_ERROR;
     }
 
-  end_old_path = strchr(old_path, ' ');
+  new_path_marker = strstr(old_path_marker, " b/");
 
-  if (end_old_path)
-    *end_old_path = '\0';
-  else
+  if (! new_path_marker)
     {
       *new_state = state_start;
       return SVN_NO_ERROR;
     }
 
-  /* The new path begins after the first slash after the old path. */
-  slash = strchr(end_old_path + 1, '/');
-
-  if (! slash)
+  if (! *(new_path_marker + 3))
     {
       *new_state = state_start;
       return SVN_NO_ERROR;
     }
 
-  /* The path starts after the slash */
-  new_path = slash + 1;
+  /* By now, we know that we have a line on the form '--git diff a/.+ b/.+'
+   * We only need the filenames when we have deleted or added empty
+   * files. In those cases the old_path and new_path is identical on the
+   * '--git diff' line.  For all other cases we fetch the filenames from
+   * other header lines. */ 
+  old_path_start = line + strlen("--git diff a/");
+  new_path_end = line + strlen(line);
+  new_path_start = old_path_start;
+
+  while (TRUE)
+    {
+      int len_old;
+      int len_new;
+
+      new_path_marker = strstr(new_path_start, " b/");
+
+      /* No new path marker, bail out. */
+      if (! new_path_marker)
+        break;
+
+      old_path_end = new_path_marker;
+      new_path_start = new_path_marker + strlen(" b/");
+
+      /* No path after the marker. */
+      if (! *new_path_start)
+        break;
+
+      len_old = old_path_end - old_path_start;
+      len_new = new_path_end - new_path_start;
+
+      /* Are the paths before and after the " b/" marker the same? */
+      if (len_old == len_new
+          && ! strncmp(old_path_start, new_path_start, len_old))
+        {
+          *old_path_end = '\0';
+          SVN_ERR(grab_filename(&patch->old_filename, old_path_start,
+                                result_pool, scratch_pool));
 
-  if (! *new_path)
-    {
-      *new_state = state_start;
-      return SVN_NO_ERROR;
+          SVN_ERR(grab_filename(&patch->new_filename, new_path_start,
+                                result_pool, scratch_pool));
+          break;
+        }
     }
 
-  SVN_ERR(grab_filename(&patch->old_filename, old_path,
-                        result_pool, scratch_pool));
-
-  SVN_ERR(grab_filename(&patch->new_filename, new_path,
-                        result_pool, scratch_pool));
-
   /* We assume that the path is only modified until we've found a 'tree'
    * header */
   patch->operation = svn_diff_op_modified;
@@ -965,6 +987,16 @@ git_minus(enum parse_state *new_state, c
 {
   /* ### Check that the path is consistent with the 'git --diff ' line. */
 
+  /* If we can find a tab, it separates the filename from
+   * the rest of the line which we can discard. */
+  char *tab = strchr(line, '\t');
+  if (tab)
+    *tab = '\0';
+
+  /* ### What if we have "--- /dev/null"? */
+  SVN_ERR(grab_filename(&patch->old_filename, line + strlen("--- a/"),
+                        result_pool, scratch_pool));
+
   *new_state = state_git_minus_seen;
   return SVN_NO_ERROR;
 }
@@ -976,6 +1008,16 @@ git_plus(enum parse_state *new_state, co
 {
   /* ### Check that the path is consistent with the 'git --diff ' line. */
 
+  /* If we can find a tab, it separates the filename from
+   * the rest of the line which we can discard. */
+  char *tab = strchr(line, '\t');
+  if (tab)
+    *tab = '\0';
+
+  /* ### What if we have "+++ /dev/null" ? */
+  SVN_ERR(grab_filename(&patch->new_filename, line + strlen("+++ b/"),
+                        result_pool, scratch_pool));
+
   *new_state = state_git_header_found;
   return SVN_NO_ERROR;
 }
@@ -987,6 +1029,9 @@ git_move_from(enum parse_state *new_stat
 {
   /* ### Check that the path is consistent with the 'git --diff ' line. */
 
+  SVN_ERR(grab_filename(&patch->old_filename, line + strlen("rename from "),
+                        result_pool, scratch_pool));
+
   *new_state = state_move_from_seen;
   return SVN_NO_ERROR;
 }
@@ -998,6 +1043,9 @@ git_move_to(enum parse_state *new_state,
 {
   /* ### Check that the path is consistent with the 'git --diff ' line. */
 
+  SVN_ERR(grab_filename(&patch->new_filename, line + strlen("rename to "),
+                        result_pool, scratch_pool));
+
   patch->operation = svn_diff_op_moved;
 
   *new_state = state_git_tree_seen;
@@ -1011,6 +1059,9 @@ git_copy_from(enum parse_state *new_stat
 {
   /* ### Check that the path is consistent with the 'git --diff ' line. */
 
+  SVN_ERR(grab_filename(&patch->old_filename, line + strlen("copy from "),
+                        result_pool, scratch_pool));
+
   *new_state = state_copy_from_seen; 
   return SVN_NO_ERROR;
 }
@@ -1022,6 +1073,9 @@ git_copy_to(enum parse_state *new_state,
 {
   /* ### Check that the path is consistent with the 'git --diff ' line. */
 
+  SVN_ERR(grab_filename(&patch->new_filename, line + strlen("copy to "),
+                        result_pool, scratch_pool));
+
   patch->operation = svn_diff_op_copied;
 
   *new_state = state_git_tree_seen;

Modified: subversion/trunk/subversion/tests/libsvn_diff/parse-diff-test.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/tests/libsvn_diff/parse-diff-test.c?rev=982534&r1=982533&r2=982534&view=diff
==============================================================================
--- subversion/trunk/subversion/tests/libsvn_diff/parse-diff-test.c (original)
+++ subversion/trunk/subversion/tests/libsvn_diff/parse-diff-test.c Thu Aug  5 10:24:23 2010
@@ -870,7 +870,7 @@ struct svn_test_descriptor_t test_funcs[
                    "test property and text unidiff parsing"),
     SVN_TEST_PASS2(test_parse_diff_symbols_in_prop_unidiff,
                    "test property diffs with odd symbols"),
-    SVN_TEST_XFAIL2(test_git_diffs_with_spaces_diff,
+    SVN_TEST_PASS2(test_git_diffs_with_spaces_diff,
                    "test git diffs with spaces in paths"),
     SVN_TEST_NULL
   };