Author: danielsh
Date: Sun Jul 26 11:59:58 2015
New Revision: 1692718

URL: http://svn.apache.org/r1692718
Log:
On the patch-exec branch:
patch: Parse mode changes out of git patches, part 1: low-level parser
functionality.

* subversion/include/svn_diff.h
  (svn_patch_t.old_executable_p, svn_patch_t.new_executable_p): New members.

* subversion/libsvn_diff/parse-diff.c
  (parse_state): New enum value 'state_old_mode_seen'.
  (parse_bits_into_executability): New helper function.
  (git_new_file, git_deleted_file): Parse the file's mode.
  (git_old_mode, git_new_mode): New state machine callback functions.
  (transitions): Hook the new callbacks.
  (svn_diff_parse_next_patch): Initialize new svn_patch_t members.

* subversion/tests/libsvn_diff/parse-diff-test.c
  (git_unidiff): Add test data for "old mode" / "new mode" parsing.
  (git_tree_and_text_unidiff): Diversify existing test data.
  (test_parse_git_diff, test_parse_git_tree_and_text_diff):
    Test the new parsing.

Modified:
    subversion/branches/patch-exec/subversion/include/svn_diff.h
    subversion/branches/patch-exec/subversion/libsvn_diff/parse-diff.c
    
subversion/branches/patch-exec/subversion/tests/libsvn_diff/parse-diff-test.c

Modified: subversion/branches/patch-exec/subversion/include/svn_diff.h
URL: 
http://svn.apache.org/viewvc/subversion/branches/patch-exec/subversion/include/svn_diff.h?rev=1692718&r1=1692717&r2=1692718&view=diff
==============================================================================
--- subversion/branches/patch-exec/subversion/include/svn_diff.h (original)
+++ subversion/branches/patch-exec/subversion/include/svn_diff.h Sun Jul 26 
11:59:58 2015
@@ -1249,6 +1249,17 @@ typedef struct svn_patch_t {
    * @since New in 1.9. */
   svn_mergeinfo_t mergeinfo;
   svn_mergeinfo_t reverse_mergeinfo;
+
+  /** The old and new executability bits, as retrieved from the patch file.
+   *
+   * #svn_tristate_unknown indicates the patch does not specify the
+   * corresponding bit.
+   */
+  /* ### This is currently not parsed out of "index" lines (where it
+   * ### serves as an assertion of the executability state, without
+   * ### changing it).  */
+  svn_tristate_t old_executable_p; 
+  svn_tristate_t new_executable_p; 
 } svn_patch_t;
 
 /** An opaque type representing an open patch file.

Modified: subversion/branches/patch-exec/subversion/libsvn_diff/parse-diff.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/patch-exec/subversion/libsvn_diff/parse-diff.c?rev=1692718&r1=1692717&r2=1692718&view=diff
==============================================================================
--- subversion/branches/patch-exec/subversion/libsvn_diff/parse-diff.c 
(original)
+++ subversion/branches/patch-exec/subversion/libsvn_diff/parse-diff.c Sun Jul 
26 11:59:58 2015
@@ -922,6 +922,7 @@ enum parse_state
    state_git_tree_seen,   /* a tree operation, rather then content change */
    state_git_minus_seen,  /* --- /dev/null; or --- a/ */
    state_git_plus_seen,   /* +++ /dev/null; or +++ a/ */
+   state_old_mode_seen,   /* old mode 100644 */
    state_move_from_seen,  /* rename from foo.c */
    state_copy_from_seen,  /* copy from foo.c */
    state_minus_seen,      /* --- foo.c */
@@ -1153,6 +1154,72 @@ git_plus(enum parse_state *new_state, ch
   return SVN_NO_ERROR;
 }
 
+/* Helper for git_old_mode() and git_new_mode().  Translate the git
+ * file mode MODE_STR into a binary "executable?" notion EXECUTABLE_P. */
+static svn_error_t *
+parse_bits_into_executability(svn_tristate_t *executable_p,
+                              const char *mode_str)
+{
+  apr_uint64_t mode;
+  SVN_ERR(svn_cstring_strtoui64(&mode, mode_str,
+                                0 /* min */,
+                                0777777 /* max: six octal digits */,
+                                010 /* radix (octal) */));
+  switch (mode & 0777)
+    {
+      case 0644:
+        *executable_p = svn_tristate_false;
+        break;
+
+      case 0755:
+        *executable_p = svn_tristate_true;
+        break;
+
+      default:
+        /* Ignore unknown values. */
+        *executable_p = svn_tristate_unknown;
+        break;
+    }
+
+  return SVN_NO_ERROR;
+}
+
+/* Parse the 'old mode ' line of a git extended unidiff. */
+static svn_error_t *
+git_old_mode(enum parse_state *new_state, char *line, svn_patch_t *patch,
+             apr_pool_t *result_pool, apr_pool_t *scratch_pool)
+{
+  SVN_ERR(parse_bits_into_executability(&patch->old_executable_p,
+                                        line + STRLEN_LITERAL("old mode ")));
+
+#ifdef SVN_DEBUG
+  /* If this assert trips, the "old mode" is neither ...644 nor ...755 . */
+  SVN_ERR_ASSERT(patch->old_executable_p != svn_tristate_unknown);
+#endif
+
+  *new_state = state_old_mode_seen;
+  return SVN_NO_ERROR;
+}
+
+/* Parse the 'new mode ' line of a git extended unidiff. */
+static svn_error_t *
+git_new_mode(enum parse_state *new_state, char *line, svn_patch_t *patch,
+             apr_pool_t *result_pool, apr_pool_t *scratch_pool)
+{
+  SVN_ERR(parse_bits_into_executability(&patch->new_executable_p,
+                                        line + STRLEN_LITERAL("new mode ")));
+
+#ifdef SVN_DEBUG
+  /* If this assert trips, the "old mode" is neither ...644 nor ...755 . */
+  SVN_ERR_ASSERT(patch->new_executable_p != svn_tristate_unknown);
+#endif
+
+  /* Don't touch patch->operation. */
+
+  *new_state = state_git_tree_seen;
+  return SVN_NO_ERROR;
+}
+
 /* Parse the 'rename from ' line of a git extended unidiff. */
 static svn_error_t *
 git_move_from(enum parse_state *new_state, char *line, svn_patch_t *patch,
@@ -1213,6 +1280,10 @@ static svn_error_t *
 git_new_file(enum parse_state *new_state, char *line, svn_patch_t *patch,
              apr_pool_t *result_pool, apr_pool_t *scratch_pool)
 {
+  SVN_ERR(
+    parse_bits_into_executability(&patch->new_executable_p,
+                                  line + STRLEN_LITERAL("new file mode ")));
+
   patch->operation = svn_diff_op_added;
 
   /* Filename already retrieved from diff --git header. */
@@ -1226,6 +1297,10 @@ static svn_error_t *
 git_deleted_file(enum parse_state *new_state, char *line, svn_patch_t *patch,
                  apr_pool_t *result_pool, apr_pool_t *scratch_pool)
 {
+  SVN_ERR(
+    parse_bits_into_executability(&patch->old_executable_p,
+                                  line + STRLEN_LITERAL("deleted file mode 
")));
+
   patch->operation = svn_diff_op_deleted;
 
   /* Filename already retrieved from diff --git header. */
@@ -1360,6 +1435,9 @@ static struct transition transitions[] =
   {"+++ b/",        state_git_minus_seen,   git_plus},
   {"+++ /dev/null", state_git_minus_seen,   git_plus},
 
+  {"old mode ",     state_git_diff_seen,    git_old_mode},
+  {"new mode ",     state_old_mode_seen,    git_new_mode},
+
   {"rename from ",  state_git_diff_seen,    git_move_from},
   {"rename to ",    state_move_from_seen,   git_move_to},
 
@@ -1394,6 +1472,8 @@ svn_diff_parse_next_patch(svn_patch_t **
     }
 
   patch = apr_pcalloc(result_pool, sizeof(*patch));
+  patch->old_executable_p = svn_tristate_unknown;
+  patch->new_executable_p = svn_tristate_unknown;
 
   pos = patch_file->next_patch_offset;
   SVN_ERR(svn_io_file_seek(patch_file->apr_file, APR_SET, &pos, scratch_pool));

Modified: 
subversion/branches/patch-exec/subversion/tests/libsvn_diff/parse-diff-test.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/patch-exec/subversion/tests/libsvn_diff/parse-diff-test.c?rev=1692718&r1=1692717&r2=1692718&view=diff
==============================================================================
--- 
subversion/branches/patch-exec/subversion/tests/libsvn_diff/parse-diff-test.c 
(original)
+++ 
subversion/branches/patch-exec/subversion/tests/libsvn_diff/parse-diff-test.c 
Sun Jul 26 11:59:58 2015
@@ -66,6 +66,8 @@ static const char *git_unidiff =
   "Index: A/C/gamma"                                                    NL
   "===================================================================" NL
   "diff --git a/A/C/gamma b/A/C/gamma"                                  NL
+  "old mode 100644"                                                     NL
+  "new mode 100755"                                                     NL
   "--- a/A/C/gamma\t(revision 2)"                                       NL
   "+++ b/A/C/gamma\t(working copy)"                                     NL
   "@@ -1 +1,2 @@"                                                       NL
@@ -114,7 +116,7 @@ static const char *git_tree_and_text_uni
   "Index: A/B/lambda"                                                   NL
   "===================================================================" NL
   "diff --git a/A/B/lambda b/A/B/lambda"                                NL
-  "deleted file mode 100644"                                            NL
+  "deleted file mode 100755"                                            NL
   "--- a/A/B/lambda\t(revision 2)"                                      NL
   "+++ /dev/null\t(working copy)"                                       NL
   "@@ -1 +0,0 @@"                                                       NL
@@ -447,6 +449,8 @@ test_parse_git_diff(apr_pool_t *pool)
   SVN_TEST_STRING_ASSERT(patch->new_filename, "A/C/gamma");
   SVN_TEST_ASSERT(patch->operation == svn_diff_op_modified);
   SVN_TEST_ASSERT(patch->hunks->nelts == 1);
+  SVN_TEST_ASSERT(patch->old_executable_p = svn_tristate_false);
+  SVN_TEST_ASSERT(patch->new_executable_p = svn_tristate_true);
 
   hunk = APR_ARRAY_IDX(patch->hunks, 0, svn_diff_hunk_t *);
 
@@ -482,6 +486,8 @@ test_parse_git_diff(apr_pool_t *pool)
   SVN_TEST_STRING_ASSERT(patch->new_filename, "new");
   SVN_TEST_ASSERT(patch->operation == svn_diff_op_added);
   SVN_TEST_ASSERT(patch->hunks->nelts == 0);
+  SVN_TEST_ASSERT(patch->old_executable_p = svn_tristate_unknown);
+  SVN_TEST_ASSERT(patch->new_executable_p = svn_tristate_false);
 
   SVN_ERR(svn_diff_close_patch_file(patch_file, pool));
 
@@ -572,6 +578,8 @@ test_parse_git_tree_and_text_diff(apr_po
   SVN_TEST_STRING_ASSERT(patch->new_filename, "/dev/null");
   SVN_TEST_ASSERT(patch->operation == svn_diff_op_deleted);
   SVN_TEST_ASSERT(patch->hunks->nelts == 1);
+  SVN_TEST_ASSERT(patch->old_executable_p = svn_tristate_true);
+  SVN_TEST_ASSERT(patch->new_executable_p = svn_tristate_unknown);
 
   hunk = APR_ARRAY_IDX(patch->hunks, 0, svn_diff_hunk_t *);
 


Reply via email to