Author: stsp
Date: Sat Nov 26 20:18:33 2011
New Revision: 1206576

URL: http://svn.apache.org/viewvc?rev=1206576&view=rev
Log:
For issue #3814 ("patch doesn't append newline to properties"), make
svn diff output a marker line "\ No newline at end of property" if
a property value doesn't end in a newline.

This will later allow 'svn patch' to create properties both with a
trailing newline (e.g. svn:mergeinfo) and without a trailing newline
(e.g. svn:eol-style).

* subversion/libsvn_client/diff.c
  (maybe_append_eol): Add output parameter had_eol, which tells the
   caller whether the property value ended with an EOL sequence.
  (display_prop_diffs): If the property value does not end with an EOL
   sequence append the line "\ No newline at end of property".

* subversion/svnlook/main.c
  (maybe_append_eol, display_prop_diffs): Same changes as libsvn_client/diff.c.
   For some reason this code is duplicated here.

* subversion/tests/cmdline/depth_tests.py
  (diff_in_depthy_wc): Adjust test expectations.

* subversion/tests/cmdline/diff_tests.py
  (make_diff_prop_val): New helper.
  (make_diff_prop_deleted, make_diff_prop_added,
   make_diff_prop_modified): Use the new helper function to create correct
    expected output for property diffs.
  (diff_with_depth): Adjust expected output.

* subversion/tests/cmdline/special_tests.py
  (diff_symlink_to_dir): Adjust expected output.

Modified:
    subversion/trunk/subversion/libsvn_client/diff.c
    subversion/trunk/subversion/svnlook/main.c
    subversion/trunk/subversion/tests/cmdline/depth_tests.py
    subversion/trunk/subversion/tests/cmdline/diff_tests.py
    subversion/trunk/subversion/tests/cmdline/special_tests.py

Modified: subversion/trunk/subversion/libsvn_client/diff.c
URL: 
http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_client/diff.c?rev=1206576&r1=1206575&r2=1206576&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_client/diff.c (original)
+++ subversion/trunk/subversion/libsvn_client/diff.c Sat Nov 26 20:18:33 2011
@@ -147,18 +147,25 @@ display_mergeinfo_diff(const char *old_m
    If TOKEN is empty, or is already terminated by an EOL marker,
    return TOKEN unmodified. Else, return a new string consisting
    of the concatenation of TOKEN and the system's default EOL marker.
-   The new string is allocated from POOL. */
+   The new string is allocated from POOL.
+   If HAD_EOL is not NULL, indicate in *HAD_EOL if the token had a EOL. */
 static const svn_string_t *
-maybe_append_eol(const svn_string_t *token, apr_pool_t *pool)
+maybe_append_eol(const svn_string_t *token, svn_boolean_t *had_eol,
+                 apr_pool_t *pool)
 {
   const char *curp;
 
+  if (had_eol)
+    *had_eol = FALSE;
+
   if (token->len == 0)
     return token;
 
   curp = token->data + token->len - 1;
   if (*curp == '\r')
     {
+      if (had_eol)
+        *had_eol = TRUE;
       return token;
     }
   else if (*curp != '\n')
@@ -167,6 +174,8 @@ maybe_append_eol(const svn_string_t *tok
     }
   else
     {
+      if (had_eol)
+        *had_eol = TRUE;
       return token;
     }
 }
@@ -665,18 +674,19 @@ display_prop_diffs(const apr_array_heade
         const svn_string_t *tmp;
         const svn_string_t *orig;
         const svn_string_t *val;
+        svn_boolean_t val_has_eol;
 
         /* The last character in a property is often not a newline.
-           Since the diff is not useful anyway for patching properties an
-           eol character is appended when needed to remove those pescious
-           ' \ No newline at end of file' lines. */
+           An eol character is appended to prevent the diff API to add a
+           ' \ No newline at end of file' line. We add 
+           ' \ No newline at end of property' manually if needed. */
         tmp = original_value ? original_value 
                              : svn_string_create_empty(iterpool);
-        orig = maybe_append_eol(tmp, iterpool);
+        orig = maybe_append_eol(tmp, NULL, iterpool);
 
         tmp = propchange->value ? propchange->value :
                                   svn_string_create_empty(iterpool);
-        val = maybe_append_eol(tmp, iterpool);
+        val = maybe_append_eol(tmp, &val_has_eol, iterpool);
 
         SVN_ERR(svn_diff_mem_string_diff(&diff, orig, val, &options,
                                          iterpool));
@@ -695,7 +705,12 @@ display_prop_diffs(const apr_array_heade
                                            svn_dirent_local_style(path,
                                                                   iterpool),
                                            encoding, orig, val, iterpool));
-
+        if (!val_has_eol)
+          {
+            const char *s = "\\ No newline at end of property" APR_EOL_STR;
+            apr_size_t len = strlen(s);
+            SVN_ERR(svn_stream_write(outstream, s, &len));
+          }
       }
     }
   svn_pool_destroy(iterpool);

Modified: subversion/trunk/subversion/svnlook/main.c
URL: 
http://svn.apache.org/viewvc/subversion/trunk/subversion/svnlook/main.c?rev=1206576&r1=1206575&r2=1206576&view=diff
==============================================================================
--- subversion/trunk/subversion/svnlook/main.c (original)
+++ subversion/trunk/subversion/svnlook/main.c Sat Nov 26 20:18:33 2011
@@ -784,18 +784,25 @@ generate_label(const char **label,
    If TOKEN is empty, or is already terminated by an EOL marker,
    return TOKEN unmodified. Else, return a new string consisting
    of the concatenation of TOKEN and the system's default EOL marker.
-   The new string is allocated from POOL. */
+   The new string is allocated from POOL.
+   If HAD_EOL is not NULL, indicate in *HAD_EOL if the token had a EOL. */
 static const svn_string_t *
-maybe_append_eol(const svn_string_t *token, apr_pool_t *pool)
+maybe_append_eol(const svn_string_t *token, svn_boolean_t *had_eol,
+                 apr_pool_t *pool)
 {
   const char *curp;
 
+  if (had_eol)
+    *had_eol = FALSE;
+
   if (token->len == 0)
     return token;
 
   curp = token->data + token->len - 1;
   if (*curp == '\r')
     {
+      if (had_eol)
+        *had_eol = TRUE;
       return token;
     }
   else if (*curp != '\n')
@@ -804,6 +811,8 @@ maybe_append_eol(const svn_string_t *tok
     }
   else
     {
+      if (had_eol)
+        *had_eol = TRUE;
       return token;
     }
 }
@@ -860,19 +869,20 @@ display_prop_diffs(const apr_array_heade
         const svn_string_t *tmp;
         const svn_string_t *orig;
         const svn_string_t *val;
+        svn_boolean_t val_has_eol;
 
         SVN_ERR(svn_stream_for_stdout(&out, pool));
 
         /* The last character in a property is often not a newline.
-           Since the diff is not useful anyway for patching properties an
-           eol character is appended when needed to remove those pescious
-           ' \ No newline at end of file' lines. */
+           An eol character is appended to prevent the diff API to add a
+           ' \ No newline at end of file' line. We add 
+           ' \ No newline at end of property' manually if needed. */
         tmp = orig_value ? orig_value : svn_string_create_empty(pool);
-        orig = maybe_append_eol(tmp, pool);
+        orig = maybe_append_eol(tmp, NULL, pool);
 
         tmp = pc->value ? pc->value :
                                   svn_string_create_empty(pool);
-        val = maybe_append_eol(tmp, pool);
+        val = maybe_append_eol(tmp, &val_has_eol, pool);
 
         SVN_ERR(svn_diff_mem_string_diff(&diff, orig, val, &options, pool));
 
@@ -888,6 +898,12 @@ display_prop_diffs(const apr_array_heade
                                            svn_dirent_local_style(path, pool),
                                            svn_cmdline_output_encoding(pool),
                                            orig, val, pool));
+        if (!val_has_eol)
+          {
+            const char *s = "\\ No newline at end of property" APR_EOL_STR;
+            apr_size_t len = strlen(s);
+            SVN_ERR(svn_stream_write(out, s, &len));
+          }
       }
     }
   return svn_cmdline_fflush(stdout);

Modified: subversion/trunk/subversion/tests/cmdline/depth_tests.py
URL: 
http://svn.apache.org/viewvc/subversion/trunk/subversion/tests/cmdline/depth_tests.py?rev=1206576&r1=1206575&r2=1206576&view=diff
==============================================================================
--- subversion/trunk/subversion/tests/cmdline/depth_tests.py (original)
+++ subversion/trunk/subversion/tests/cmdline/depth_tests.py Sat Nov 26 
20:18:33 2011
@@ -1076,7 +1076,8 @@ def diff_in_depthy_wc(sbox):
     "___________________________________________________________________\n",
     "Deleted: foo\n",
     "## -1 +0,0 ##\n",
-    "-foo-val\n"]
+    "-foo-val\n",
+    "\\ No newline at end of property\n"]
 
   os.chdir(wc_empty)
 

Modified: subversion/trunk/subversion/tests/cmdline/diff_tests.py
URL: 
http://svn.apache.org/viewvc/subversion/trunk/subversion/tests/cmdline/diff_tests.py?rev=1206576&r1=1206575&r2=1206576&view=diff
==============================================================================
--- subversion/trunk/subversion/tests/cmdline/diff_tests.py (original)
+++ subversion/trunk/subversion/tests/cmdline/diff_tests.py Sat Nov 26 20:18:33 
2011
@@ -146,15 +146,20 @@ def make_diff_prop_header(path):
     "___________________________________________________________________\n"
   ]
 
+def make_diff_prop_val(plus_minus, pval):
+  "Return diff for prop value PVAL, with leading PLUS_MINUS (+ or -)."
+  if len(pval) > 0 and pval[-1] != '\n':
+    return [plus_minus + pval + "\n","\\ No newline at end of property\n"]
+  return [plus_minus + pval]
+  
 def make_diff_prop_deleted(pname, pval):
   """Return a property diff for deletion of property PNAME, old value PVAL.
      PVAL is a single string with no embedded newlines.  Return the result
      as a list of newline-terminated strings."""
   return [
     "Deleted: " + pname + "\n",
-    "## -1 +0,0 ##\n",
-    "-" + pval + "\n"
-  ]
+    "## -1 +0,0 ##\n"
+  ] + make_diff_prop_val("-", pval)
 
 def make_diff_prop_added(pname, pval):
   """Return a property diff for addition of property PNAME, new value PVAL.
@@ -163,8 +168,7 @@ def make_diff_prop_added(pname, pval):
   return [
     "Added: " + pname + "\n",
     "## -0,0 +1 ##\n",
-    "+" + pval + "\n"
-  ]
+  ] + make_diff_prop_val("+", pval)
 
 def make_diff_prop_modified(pname, pval1, pval2):
   """Return a property diff for modification of property PNAME, old value
@@ -173,9 +177,7 @@ def make_diff_prop_modified(pname, pval1
   return [
     "Modified: " + pname + "\n",
     "## -1 +1 ##\n",
-    "-" + pval1 + "\n",
-    "+" + pval2 + "\n"
-  ]
+  ] + make_diff_prop_val("-", pval1) + make_diff_prop_val("+", pval2)
 
 ######################################################################
 # Diff output checker
@@ -2853,18 +2855,18 @@ def diff_with_depth(sbox):
   A_header = make_diff_header('A', "revision 1", "working copy")
   B_header = make_diff_header(B_path, "revision 1", "working copy")
 
-  expected_empty = svntest.verify.UnorderedOutput(dot_header + diff[:6])
-  expected_files = svntest.verify.UnorderedOutput(dot_header + diff[:6]
-                                                  + iota_header + diff[7:12])
-  expected_immediates = svntest.verify.UnorderedOutput(dot_header + diff[:6]
+  expected_empty = svntest.verify.UnorderedOutput(dot_header + diff[:7])
+  expected_files = svntest.verify.UnorderedOutput(dot_header + diff[:7]
+                                                  + iota_header + diff[8:14])
+  expected_immediates = svntest.verify.UnorderedOutput(dot_header + diff[:7]
                                                        + iota_header
-                                                       + diff[7:12]
-                                                       +  A_header + 
diff[8:18])
-  expected_infinity = svntest.verify.UnorderedOutput(dot_header + diff[:6]
+                                                       + diff[8:14]
+                                                       + A_header + 
diff[15:21])
+  expected_infinity = svntest.verify.UnorderedOutput(dot_header + diff[:7]
                                                        + iota_header
-                                                       + diff[7:12]
-                                                       +  A_header + diff[8:18]
-                                                       + B_header + diff[12:])
+                                                       + diff[8:14]
+                                                       + A_header + diff[15:21]
+                                                       + B_header + diff[22:])
 
   os.chdir(sbox.wc_dir)
 
@@ -2900,18 +2902,18 @@ def diff_with_depth(sbox):
   A_header = make_diff_header('A', "revision 1", "revision 2")
   B_header = make_diff_header(B_path, "revision 1", "revision 2")
 
-  expected_empty = svntest.verify.UnorderedOutput(dot_header + diff[:6])
-  expected_files = svntest.verify.UnorderedOutput(dot_header + diff[:6]
-                                                  + iota_header + diff[7:12])
-  expected_immediates = svntest.verify.UnorderedOutput(dot_header + diff[:6]
+  expected_empty = svntest.verify.UnorderedOutput(dot_header + diff[:7])
+  expected_files = svntest.verify.UnorderedOutput(dot_header + diff[:7]
+                                                  + iota_header + diff[8:14])
+  expected_immediates = svntest.verify.UnorderedOutput(dot_header + diff[:7]
                                                        + iota_header
-                                                       + diff[7:12]
-                                                       +  A_header + 
diff[8:18])
+                                                       + diff[8:14]
+                                                       + A_header + 
diff[15:21])
   expected_infinity = svntest.verify.UnorderedOutput(dot_header + diff[:6]
                                                        + iota_header
-                                                       + diff[7:12]
-                                                       +  A_header + diff[8:18]
-                                                       + B_header + diff[12:])
+                                                       + diff[8:14]
+                                                       + A_header + diff[15:21]
+                                                       + B_header + diff[22:])
 
   # Test repos-repos diff.
   svntest.actions.run_and_verify_svn(None, expected_empty, [],
@@ -2944,10 +2946,10 @@ def diff_with_depth(sbox):
     make_diff_prop_header(".") + \
     make_diff_prop_modified("foo1", "bar1", "baz1")
 
-  expected_empty = svntest.verify.UnorderedOutput(diff_wc_repos[43:])
-  expected_files = svntest.verify.UnorderedOutput(diff_wc_repos[29:])
-  expected_immediates = svntest.verify.UnorderedOutput(diff_wc_repos[11:22]
-                                                       +diff_wc_repos[29:])
+  expected_empty = svntest.verify.UnorderedOutput(diff_wc_repos[49:])
+  expected_files = svntest.verify.UnorderedOutput(diff_wc_repos[33:])
+  expected_immediates = svntest.verify.UnorderedOutput(diff_wc_repos[13:26]
+                                                       +diff_wc_repos[33:])
   expected_infinity = svntest.verify.UnorderedOutput(diff_wc_repos[:])
 
   svntest.actions.run_and_verify_svn(None, None, [],

Modified: subversion/trunk/subversion/tests/cmdline/special_tests.py
URL: 
http://svn.apache.org/viewvc/subversion/trunk/subversion/tests/cmdline/special_tests.py?rev=1206576&r1=1206575&r2=1206576&view=diff
==============================================================================
--- subversion/trunk/subversion/tests/cmdline/special_tests.py (original)
+++ subversion/trunk/subversion/tests/cmdline/special_tests.py Sat Nov 26 
20:18:33 2011
@@ -551,7 +551,9 @@ def diff_symlink_to_dir(sbox):
     "___________________________________________________________________\n",
     "Added: svn:special\n",
     "## -0,0 +1 ##\n",
-    "+*\n" ]
+    "+*\n",
+    "\\ No newline at end of property\n"
+  ]
   svntest.actions.run_and_verify_svn(None, expected_output, [], 'diff',
                                      '.')
   # We should get the same output if we the diff the symlink itself.


Reply via email to