Author: dannas
Date: Sun Jun  6 14:49:15 2010
New Revision: 951871

URL: http://svn.apache.org/viewvc?rev=951871&view=rev
Log:
First small step towards using the 'git unidiff' format for 'svn diff'.

The parts that writes to the output stream are ifdef'd with
SVN_EXPERIMENTAL_PATCH since five diff-tests needs to be adjusted and I
don't want to change the testsuite before we're 100 % certain that we
want to use the git diff format as our standard format and not as an
optional one.

* subversion/libsvn_client/diff.c
  (print_git_diff_header): New.
  (diff_cmd_baton): Add field 'deleted'.
  (diff_content_changed): Call print_git_diff_header() and adjust the
    labels before asking libsvn_diff to produce the actual diff.
  (diff_file_deleted_with_diff): Note in the diff_cmd_baton that we have
    a deleted path.
  (svn_client_diff5
   svn_client_diff_peg5): Initialize diff_cmd_baton.deleted to FALSE.

Modified:
    subversion/trunk/subversion/libsvn_client/diff.c

Modified: subversion/trunk/subversion/libsvn_client/diff.c
URL: 
http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_client/diff.c?rev=951871&r1=951870&r2=951871&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_client/diff.c (original)
+++ subversion/trunk/subversion/libsvn_client/diff.c Sun Jun  6 14:49:15 2010
@@ -306,6 +306,64 @@ display_prop_diffs(const apr_array_heade
   return SVN_NO_ERROR;
 }
 
+#ifdef SVN_EXPERIMENTAL_PATCH
+/*
+ * Print a git diff header for PATH to the stream OS using HEADER_ENCODING.
+ * The header lines are determined from what operation is performed on the
+ * file using DELETED, COPIED, MOVED and ADDED. When the
+ * operation is a move or copy, copyfrom_path is used to determine the
+ * source. All allocations are done in RESULT_POOL. */
+static svn_error_t *
+print_git_diff_header(svn_stream_t *os, const char *copyfrom_path,
+                      svn_boolean_t deleted, svn_boolean_t copied,
+                      svn_boolean_t moved, svn_boolean_t added, 
+                      const char *header_encoding, const char *path, 
+                      apr_pool_t *result_pool)
+{
+  if (copied)
+    {
+      SVN_ERR(svn_stream_printf_from_utf8(os, header_encoding, result_pool,
+                                          "diff --git a/%s b/%s%s",
+                                          copyfrom_path, path, APR_EOL_STR));
+      SVN_ERR(svn_stream_printf_from_utf8(os, header_encoding, result_pool,
+                                          "copy from %s%s", path, 
APR_EOL_STR));
+      SVN_ERR(svn_stream_printf_from_utf8(os, header_encoding, result_pool,
+                                          "copy to %s%s", copyfrom_path, 
+                                          APR_EOL_STR));
+    }
+  else if (moved)
+    {
+      SVN_ERR(svn_stream_printf_from_utf8(os, header_encoding, result_pool,
+                                          "diff --git a/%s b/%s%s",
+                                          copyfrom_path, path, APR_EOL_STR));
+      SVN_ERR(svn_stream_printf_from_utf8(os, header_encoding, result_pool,
+                                          "rename from %s%s", path, 
+                                          APR_EOL_STR));
+      SVN_ERR(svn_stream_printf_from_utf8(os, header_encoding, result_pool,
+                                          "rename to %s%s", copyfrom_path, 
+                                          APR_EOL_STR));
+    }
+  else if (deleted)
+    {
+      SVN_ERR(svn_stream_printf_from_utf8(os, header_encoding, result_pool,
+                                          "diff --git a/%s b/%s%s",
+                                          path, path, APR_EOL_STR));
+      SVN_ERR(svn_stream_printf_from_utf8(os, header_encoding, result_pool,
+                                          "deleted file mode 10644"
+                                          APR_EOL_STR));
+    }
+  else if (added)
+    {
+      SVN_ERR(svn_stream_printf_from_utf8(os, header_encoding, result_pool,
+                                          "diff --git a/%s b/%s%s",
+                                          path, path, APR_EOL_STR));
+      SVN_ERR(svn_stream_printf_from_utf8(os, header_encoding, result_pool,
+                                          "new file mode 10644" APR_EOL_STR));
+    }
+  return SVN_NO_ERROR;
+}
+#endif
+
 
 /*-----------------------------------------------------------------*/
 
@@ -365,6 +423,10 @@ struct diff_cmd_baton {
   /* The directory that diff target paths should be considered as
      relative to for output generation (see issue #2723). */
   const char *relative_to_dir;
+
+  /* ### Add moved, copied and added fields when we can detect those
+   * ### properly. */
+  svn_boolean_t deleted;
 };
 
 /* Generate a label for the diff output for file PATH at revision REVNUM.
@@ -535,6 +597,8 @@ diff_content_changed(const char *path,
               (os, diff_cmd_baton->header_encoding, subpool,
                "Index: %s" APR_EOL_STR "%s" APR_EOL_STR, path, equal_string));
 
+      /* ### Print git diff headers. */
+
       SVN_ERR(svn_stream_printf_from_utf8
               (os, diff_cmd_baton->header_encoding, subpool,
                _("Cannot display: file marked as a binary type.%s"),
@@ -577,6 +641,11 @@ diff_content_changed(const char *path,
       /* Close the stream (flush) */
       SVN_ERR(svn_stream_close(os));
 
+      /* ### Do we want to add git diff headers here too? I'd say no. The
+       * ### 'Index' and '===' line is something subversion has added. The rest
+       * ### is up to the external diff application. We may be dealing with
+       * ### a non-git compatible diff application.*/
+
       SVN_ERR(svn_io_run_diff2(".",
                                diff_cmd_baton->options.for_external.argv,
                                diff_cmd_baton->options.for_external.argc,
@@ -600,6 +669,31 @@ diff_content_changed(const char *path,
                   (os, diff_cmd_baton->header_encoding, subpool,
                    "Index: %s" APR_EOL_STR "%s" APR_EOL_STR,
                    path, equal_string));
+#ifdef SVN_EXPERIMENTAL_PATCH
+          /* ### We need to adjust the labels to comply with the git unidiff
+           * ### standard. The labels must be adjusted for the case of an
+           * ### add too. 
+           * 
+           * ### If the paths has different length, the revisions will not
+           * ### be in the same column. Is that a problem? */
+          if (diff_cmd_baton->deleted)
+            {
+              label1 = diff_label(apr_psprintf(subpool, "a/%s", path1), rev1,
+                                  subpool);
+              label2 = diff_label("/dev/null", rev2, subpool);
+            }
+          
+          /* ### Passing FALSE for added, copied and moved and NULL for
+           * ### copyfrom_path since we're only dealing with deleted paths for
+           * ### git headers at this early point. */
+          SVN_ERR(print_git_diff_header(os, NULL, /* copyfrom_path */
+                                        diff_cmd_baton->deleted,
+                                        FALSE, /* copied */
+                                        FALSE, /* moved */
+                                        FALSE, /* added */
+                                        diff_cmd_baton->header_encoding,
+                                        path, subpool));
+#endif
           /* Output the actual diff */
           SVN_ERR(svn_diff_file_output_unified3
                   (os, diff, tmpfile1, tmpfile2, label1, label2,
@@ -715,6 +809,7 @@ diff_file_deleted_with_diff(const char *
                             apr_pool_t *scratch_pool)
 {
   struct diff_cmd_baton *diff_cmd_baton = diff_baton;
+  diff_cmd_baton->deleted = TRUE;
 
   /* We don't list all the deleted properties. */
   return diff_file_changed(local_dir_abspath, state, NULL, tree_conflicted,
@@ -1748,6 +1843,7 @@ svn_client_diff5(const apr_array_header_
   diff_cmd_baton.force_empty = FALSE;
   diff_cmd_baton.force_binary = ignore_content_type;
   diff_cmd_baton.relative_to_dir = relative_to_dir;
+  diff_cmd_baton.deleted = FALSE;
 
   return do_diff(&diff_params, &diff_callbacks, &diff_cmd_baton, ctx, pool);
 }
@@ -1814,6 +1910,7 @@ svn_client_diff_peg5(const apr_array_hea
   diff_cmd_baton.force_empty = FALSE;
   diff_cmd_baton.force_binary = ignore_content_type;
   diff_cmd_baton.relative_to_dir = relative_to_dir;
+  diff_cmd_baton.deleted = FALSE;
 
   return do_diff(&diff_params, &diff_callbacks, &diff_cmd_baton, ctx, pool);
 }


Reply via email to