subversion-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From s...@apache.org
Subject svn commit: r1600096 - in /subversion/trunk/subversion: include/svn_diff.h libsvn_diff/parse-diff.c
Date Wed, 04 Jun 2014 10:48:42 GMT
Author: stsp
Date: Wed Jun  4 10:48:42 2014
New Revision: 1600096

URL: http://svn.apache.org/r1600096
Log:
Make the diff parser return mergeinfo data contained in a diff.
This requires a special parsing step for pretty-printed mergeinfo
diff data, which is partly affected by i18n.

This is a prerequisite for eventual svn:mergeinfo support in 'svn patch',
tracked as issue #3747. However, making 'svn patch' apply mergeinfo
changes will first require making 'svn patch' mirror the results of
'svn merge' much more closely. Among other things, 'svn patch' needs
smarter handling of tree changes. E.g. copies created by a merge should
be created as copies by 'svn patch'. Currently, 'svn patch' transforms
copies into additions. It's unclear to what extent 'svn patch' could
emulate 'svn merge' because the unidiff format and it's various extensions
are quite different to Subversion's internal merge editor.

A grumpier type of SVN developer might even insinuate that svn:mergeinfo
is far from useful in the context of 'svn patch'. However, making the
diff parser return mergeinfo data should not contradict this notion,
nor should it make future research into perfect patch strategies impossible.

Modified:
    subversion/trunk/subversion/include/svn_diff.h
    subversion/trunk/subversion/libsvn_diff/parse-diff.c

Modified: subversion/trunk/subversion/include/svn_diff.h
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/include/svn_diff.h?rev=1600096&r1=1600095&r2=1600096&view=diff
==============================================================================
--- subversion/trunk/subversion/include/svn_diff.h (original)
+++ subversion/trunk/subversion/include/svn_diff.h Wed Jun  4 10:48:42 2014
@@ -55,6 +55,7 @@
 #include "svn_types.h"
 #include "svn_io.h"       /* for svn_stream_t */
 #include "svn_string.h"
+#include "svn_mergeinfo.h"
 
 #ifdef __cplusplus
 extern "C" {
@@ -1141,6 +1142,14 @@ typedef struct svn_patch_t {
   /**
    * Indicates whether the patch is being interpreted in reverse. */
   svn_boolean_t reverse;
+
+  /**
+   * Mergeinfo parsed from svn:mergeinfo diff data, with one entry for
+   * forward merges and one for reverse merges.
+   * Either entry can be @c NULL if no such merges are part of the diff.
+   * @since New in 1.9. */
+  svn_mergeinfo_t mergeinfo;
+  svn_mergeinfo_t reverse_mergeinfo;
 } svn_patch_t;
 
 /** An opaque type representing an open patch file.

Modified: subversion/trunk/subversion/libsvn_diff/parse-diff.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_diff/parse-diff.c?rev=1600096&r1=1600095&r2=1600096&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_diff/parse-diff.c (original)
+++ subversion/trunk/subversion/libsvn_diff/parse-diff.c Wed Jun  4 10:48:42 2014
@@ -35,6 +35,8 @@
 #include "svn_utf.h"
 #include "svn_dirent_uri.h"
 #include "svn_diff.h"
+#include "svn_ctype.h"
+#include "svn_mergeinfo.h"
 
 #include "private/svn_eol_private.h"
 #include "private/svn_dep_compat.h"
@@ -448,6 +450,127 @@ parse_prop_name(const char **prop_name, 
   return SVN_NO_ERROR;
 }
 
+
+/* A helper function to parse svn:mergeinfo diffs.
+ *
+ * These diffs use a special pretty-print format, for instance:
+ *
+ * Added: svn:mergeinfo
+ * ## -0,0 +0,1 ##
+ *   Merged /trunk:r2-3
+ *
+ * The hunk header has the following format:
+ * ## -0,NUMBER_OF_REVERSE_MERGES +0,NUMBER_OF_FORWARD_MERGES ##
+ *
+ * At this point, the number of reverse merges has already been
+ * parsed into HUNK->ORIGINAL_LENGTH, and the number of forward
+ * merges has been parsed into HUNK->MODIFIED_LENGTH.
+ *
+ * The header is followed by a list of mergeinfo, one path per line.
+ * This function parses such lines. Lines describing reverse merges
+ * appear first, and then all lines describing forward merges appear.
+ *
+ * Parts of the line are affected by i18n. The words 'Merged'
+ * and 'Reverse-merged' can appear in any language and at any
+ * position within the line. We can only assume that a leading
+ * '/' starts the merge source path, the path is followed by
+ * ":r", which in turn is followed by a mergeinfo revision range,
+ *  which is terminated by whitespace or end-of-string.
+ *
+ * If the current line meets the above criteria and we're able
+ * to parse valid mergeinfo from it, the resulting mergeinfo
+ * is added to patch->mergeinfo or patch->reverse_mergeinfo,
+ * and we proceed to the next line.
+ */
+static svn_error_t *
+parse_mergeinfo(svn_boolean_t *found_mergeinfo,
+                svn_stringbuf_t *line,
+                svn_diff_hunk_t *hunk,
+                svn_patch_t *patch,
+                apr_pool_t *result_pool,
+                apr_pool_t *scratch_pool)
+{
+  apr_uint64_t reverse_merges = hunk->original_length;
+  apr_uint64_t forward_merges = hunk->modified_length;
+  char *slash = strchr(line->data, '/');
+  char *colon = strrchr(line->data, ':');
+
+  *found_mergeinfo = FALSE;
+
+  if (slash && colon && colon[1] == 'r' && slash < colon)
+    {
+      svn_stringbuf_t *input;
+      svn_mergeinfo_t mergeinfo = NULL;
+      char *s;
+      svn_error_t *err;
+
+      input = svn_stringbuf_create_ensure(line->len, scratch_pool);
+
+      /* Copy the merge source path + colon */
+      s = slash;
+      while (s <= colon)
+        {
+          svn_stringbuf_appendbyte(input, *s);
+          s++;
+        }
+
+      /* skip 'r' after colon */
+      s++;
+
+      /* Copy the revision range. */
+      while (s < line->data + line->len)
+        {
+          if (svn_ctype_isspace(*s))
+            break;
+          svn_stringbuf_appendbyte(input, *s);
+          s++;
+        }
+
+      err = svn_mergeinfo_parse(&mergeinfo, input->data, result_pool);
+      if (err && err->apr_err == SVN_ERR_MERGEINFO_PARSE_ERROR)
+        {
+          svn_error_clear(err);
+          mergeinfo = NULL;
+        }
+      else
+        SVN_ERR(err);
+                            
+      if (mergeinfo)
+        {
+          svn_boolean_t is_forward_merge = TRUE;
+
+          if (reverse_merges > 0)
+            {
+              if (patch->reverse_mergeinfo == NULL)
+                patch->reverse_mergeinfo = mergeinfo;
+              
+              is_forward_merge = (apr_hash_count(patch->reverse_mergeinfo)
+                                  > reverse_merges);
+              if (!is_forward_merge)
+                SVN_ERR(svn_mergeinfo_merge2(patch->reverse_mergeinfo,
+                                             mergeinfo,
+                                             result_pool,
+                                             scratch_pool));
+            }
+
+          if (forward_merges > 0 && is_forward_merge)
+            {
+              if (patch->mergeinfo == NULL)
+                patch->mergeinfo = mergeinfo;
+              else
+                SVN_ERR(svn_mergeinfo_merge2(patch->mergeinfo,
+                                             mergeinfo,
+                                             result_pool,
+                                             scratch_pool));
+            }
+
+          *found_mergeinfo = TRUE;
+        }
+    }
+
+  return SVN_NO_ERROR;
+}
+
 /* Return the next *HUNK from a PATCH in APR_FILE.
  * If no hunk can be found, set *HUNK to NULL.
  * Set IS_PROPERTY to TRUE if we have a property hunk. If the returned HUNK
@@ -577,6 +700,17 @@ parse_next_hunk(svn_diff_hunk_t **hunk,
           continue;
         }
 
+      if (in_hunk && *is_property && *prop_name &&
+          strcmp(*prop_name, SVN_PROP_MERGEINFO) == 0)
+        {
+          svn_boolean_t found_mergeinfo;
+
+          SVN_ERR(parse_mergeinfo(&found_mergeinfo, line, *hunk, patch,
+                                  result_pool, iterpool));
+          if (found_mergeinfo)
+            continue; /* Proceed to the next line in the patch. */
+        }
+
       if (in_hunk)
         {
           char c;
@@ -1169,6 +1303,13 @@ parse_hunks(svn_patch_t *patch, apr_file
             prop_name = last_prop_name;
           else
             last_prop_name = prop_name;
+
+          /* Skip svn:mergeinfo properties.
+           * Mergeinfo data cannot be represented as a hunk and
+           * is therefore stored in PATCH itself. */
+          if (strcmp(prop_name, SVN_PROP_MERGEINFO) == 0)
+            continue;
+
           SVN_ERR(add_property_hunk(patch, prop_name, hunk, prop_operation,
                                     result_pool));
         }



Mime
View raw message