You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by ju...@apache.org on 2015/09/28 18:03:15 UTC
svn commit: r1705712 [2/3] - in /subversion/branches/move-tracking-2: ./
subversion/ subversion/include/ subversion/include/private/
subversion/libsvn_client/ subversion/libsvn_diff/
subversion/libsvn_fs_base/ subversion/libsvn_fs_fs/ subversion/libsvn...
Modified: subversion/branches/move-tracking-2/subversion/libsvn_diff/parse-diff.c
URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/libsvn_diff/parse-diff.c?rev=1705712&r1=1705711&r2=1705712&view=diff
==============================================================================
--- subversion/branches/move-tracking-2/subversion/libsvn_diff/parse-diff.c (original)
+++ subversion/branches/move-tracking-2/subversion/libsvn_diff/parse-diff.c Mon Sep 28 16:03:14 2015
@@ -40,8 +40,13 @@
#include "private/svn_eol_private.h"
#include "private/svn_dep_compat.h"
+#include "private/svn_diff_private.h"
#include "private/svn_sorts_private.h"
+#include "diff.h"
+
+#include "svn_private_config.h"
+
/* Helper macro for readability */
#define starts_with(str, start) \
(strncmp((str), (start), strlen(start)) == 0)
@@ -80,6 +85,10 @@ struct svn_diff_hunk_t {
/* Number of lines of leading and trailing hunk context. */
svn_linenum_t leading_context;
svn_linenum_t trailing_context;
+
+ /* Did we see a 'file does not end with eol' marker in this hunk? */
+ svn_boolean_t original_no_final_eol;
+ svn_boolean_t modified_no_final_eol;
};
struct svn_diff_binary_patch_t {
@@ -100,6 +109,120 @@ struct svn_diff_binary_patch_t {
svn_filesize_t dst_filesize; /* Expanded/final size */
};
+/* Common guts of svn_diff_hunk__create_adds_single_line() and
+ * svn_diff_hunk__create_deletes_single_line().
+ *
+ * ADD is TRUE if adding and FALSE if deleting.
+ */
+static svn_error_t *
+add_or_delete_single_line(svn_diff_hunk_t **hunk_out,
+ const char *line,
+ svn_patch_t *patch,
+ svn_boolean_t add,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ svn_diff_hunk_t *hunk = apr_palloc(result_pool, sizeof(*hunk));
+ static const char *hunk_header[] = { "@@ -1 +0,0 @@\n", "@@ -0,0 +1 @@\n" };
+ const apr_size_t header_len = strlen(hunk_header[add]);
+ const apr_size_t len = strlen(line);
+ const apr_size_t end = header_len + (1 + len); /* The +1 is for the \n. */
+ svn_stringbuf_t *buf = svn_stringbuf_create_ensure(end + 1, scratch_pool);
+
+ hunk->patch = patch;
+
+ /* hunk->apr_file is created below. */
+
+ hunk->diff_text_range.start = header_len;
+ hunk->diff_text_range.current = header_len;
+
+ if (add)
+ {
+ hunk->original_text_range.start = 0; /* There's no "original" text. */
+ hunk->original_text_range.current = 0;
+ hunk->original_text_range.end = 0;
+ hunk->original_no_final_eol = FALSE;
+
+ hunk->modified_text_range.start = header_len;
+ hunk->modified_text_range.current = header_len;
+ hunk->modified_text_range.end = end;
+ hunk->modified_no_final_eol = TRUE;
+
+ hunk->original_start = 0;
+ hunk->original_length = 0;
+
+ hunk->modified_start = 1;
+ hunk->modified_length = 1;
+ }
+ else /* delete */
+ {
+ hunk->original_text_range.start = header_len;
+ hunk->original_text_range.current = header_len;
+ hunk->original_text_range.end = end;
+ hunk->original_no_final_eol = TRUE;
+
+ hunk->modified_text_range.start = 0; /* There's no "original" text. */
+ hunk->modified_text_range.current = 0;
+ hunk->modified_text_range.end = 0;
+ hunk->modified_no_final_eol = FALSE;
+
+ hunk->original_start = 1;
+ hunk->original_length = 1;
+
+ hunk->modified_start = 0;
+ hunk->modified_length = 0; /* setting to '1' works too */
+ }
+
+ hunk->leading_context = 0;
+ hunk->trailing_context = 0;
+
+ /* Create APR_FILE and put just a hunk in it (without a diff header).
+ * Save the offset of the last byte of the diff line. */
+ svn_stringbuf_appendbytes(buf, hunk_header[add], header_len);
+ svn_stringbuf_appendbyte(buf, add ? '+' : '-');
+ svn_stringbuf_appendbytes(buf, line, len);
+ svn_stringbuf_appendbyte(buf, '\n');
+ svn_stringbuf_appendcstr(buf, "\\ No newline at end of hunk\n");
+
+ hunk->diff_text_range.end = buf->len;
+
+ SVN_ERR(svn_io_open_unique_file3(&hunk->apr_file, NULL /* filename */,
+ NULL /* system tempdir */,
+ svn_io_file_del_on_pool_cleanup,
+ result_pool, scratch_pool));
+ SVN_ERR(svn_io_file_write_full(hunk->apr_file,
+ buf->data, buf->len,
+ NULL, scratch_pool));
+ /* No need to seek. */
+
+ *hunk_out = hunk;
+ return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_diff_hunk__create_adds_single_line(svn_diff_hunk_t **hunk_out,
+ const char *line,
+ svn_patch_t *patch,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ SVN_ERR(add_or_delete_single_line(hunk_out, line, patch, TRUE,
+ result_pool, scratch_pool));
+ return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_diff_hunk__create_deletes_single_line(svn_diff_hunk_t **hunk_out,
+ const char *line,
+ svn_patch_t *patch,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ SVN_ERR(add_or_delete_single_line(hunk_out, line, patch, FALSE,
+ result_pool, scratch_pool));
+ return SVN_NO_ERROR;
+}
+
void
svn_diff_hunk_reset_diff_text(svn_diff_hunk_t *hunk)
{
@@ -160,6 +283,217 @@ svn_diff_hunk_get_trailing_context(const
return hunk->trailing_context;
}
+/* Baton for the base85 stream implementation */
+struct base85_baton_t
+{
+ apr_file_t *file;
+ apr_pool_t *iterpool;
+ char buffer[52]; /* Bytes on current line */
+ apr_off_t next_pos; /* Start position of next line */
+ apr_off_t end_pos; /* Position after last line */
+ apr_size_t buf_size; /* Bytes available (52 unless at eof) */
+ apr_size_t buf_pos; /* Bytes in linebuffer */
+ svn_boolean_t done; /* At eof? */
+};
+
+/* Implements svn_read_fn_t for the base85 read stream */
+static svn_error_t *
+read_handler_base85(void *baton, char *buffer, apr_size_t *len)
+{
+ struct base85_baton_t *b85b = baton;
+ apr_pool_t *iterpool = b85b->iterpool;
+ apr_size_t remaining = *len;
+ char *dest = buffer;
+
+ svn_pool_clear(iterpool);
+
+ if (b85b->done)
+ {
+ *len = 0;
+ return SVN_NO_ERROR;
+ }
+
+ while (remaining && (b85b->buf_size > b85b->buf_pos
+ || b85b->next_pos < b85b->end_pos))
+ {
+ svn_stringbuf_t *line;
+ svn_boolean_t at_eof;
+
+ apr_size_t available = b85b->buf_size - b85b->buf_pos;
+ if (available)
+ {
+ apr_size_t n = (remaining < available) ? remaining : available;
+
+ memcpy(dest, b85b->buffer + b85b->buf_pos, n);
+ dest += n;
+ remaining -= n;
+ b85b->buf_pos += n;
+
+ if (!remaining)
+ return SVN_NO_ERROR; /* *len = OK */
+ }
+
+ if (b85b->next_pos >= b85b->end_pos)
+ break; /* At EOF */
+ SVN_ERR(svn_io_file_seek(b85b->file, APR_SET, &b85b->next_pos,
+ iterpool));
+ SVN_ERR(svn_io_file_readline(b85b->file, &line, NULL, &at_eof,
+ APR_SIZE_MAX, iterpool, iterpool));
+ if (at_eof)
+ b85b->next_pos = b85b->end_pos;
+ else
+ {
+ b85b->next_pos = 0;
+ SVN_ERR(svn_io_file_seek(b85b->file, APR_CUR, &b85b->next_pos,
+ iterpool));
+ }
+
+ if (line->len && line->data[0] >= 'A' && line->data[0] <= 'Z')
+ b85b->buf_size = line->data[0] - 'A' + 1;
+ else if (line->len && line->data[0] >= 'a' && line->data[0] <= 'z')
+ b85b->buf_size = line->data[0] - 'a' + 26 + 1;
+ else
+ return svn_error_create(SVN_ERR_DIFF_UNEXPECTED_DATA, NULL,
+ _("Unexpected data in base85 section"));
+
+ if (b85b->buf_size < 52)
+ b85b->next_pos = b85b->end_pos; /* Handle as EOF */
+
+ SVN_ERR(svn_diff__base85_decode_line(b85b->buffer, b85b->buf_size,
+ line->data + 1, line->len - 1,
+ iterpool));
+ b85b->buf_pos = 0;
+ }
+
+ *len -= remaining;
+ b85b->done = TRUE;
+
+ return SVN_NO_ERROR;
+}
+
+/* Implements svn_close_fn_t for the base85 read stream */
+static svn_error_t *
+close_handler_base85(void *baton)
+{
+ struct base85_baton_t *b85b = baton;
+
+ svn_pool_destroy(b85b->iterpool);
+
+ return SVN_NO_ERROR;
+}
+
+/* Gets a stream that reads decoded base85 data from a segment of a file.
+ The current implementation might assume that both start_pos and end_pos
+ are located at line boundaries. */
+static svn_stream_t *
+get_base85_data_stream(apr_file_t *file,
+ apr_off_t start_pos,
+ apr_off_t end_pos,
+ apr_pool_t *result_pool)
+{
+ struct base85_baton_t *b85b = apr_pcalloc(result_pool, sizeof(*b85b));
+ svn_stream_t *base85s = svn_stream_create(b85b, result_pool);
+
+ b85b->file = file;
+ b85b->iterpool = svn_pool_create(result_pool);
+ b85b->next_pos = start_pos;
+ b85b->end_pos = end_pos;
+
+ svn_stream_set_read2(base85s, NULL /* only full read support */,
+ read_handler_base85);
+ svn_stream_set_close(base85s, close_handler_base85);
+ return base85s;
+}
+
+/* Baton for the length verification stream functions */
+struct length_verify_baton_t
+{
+ svn_stream_t *inner;
+ svn_filesize_t remaining;
+};
+
+/* Implements svn_read_fn_t for the length verification stream */
+static svn_error_t *
+read_handler_length_verify(void *baton, char *buffer, apr_size_t *len)
+{
+ struct length_verify_baton_t *lvb = baton;
+ apr_size_t requested_len = *len;
+
+ SVN_ERR(svn_stream_read_full(lvb->inner, buffer, len));
+
+ if (*len > lvb->remaining)
+ return svn_error_create(SVN_ERR_DIFF_UNEXPECTED_DATA, NULL,
+ _("Base85 data expands to longer than declared "
+ "filesize"));
+ else if (requested_len > *len && *len != lvb->remaining)
+ return svn_error_create(SVN_ERR_DIFF_UNEXPECTED_DATA, NULL,
+ _("Base85 data expands to smaller than declared "
+ "filesize"));
+
+ lvb->remaining -= *len;
+
+ return SVN_NO_ERROR;
+}
+
+/* Implements svn_close_fn_t for the length verification stream */
+static svn_error_t *
+close_handler_length_verify(void *baton)
+{
+ struct length_verify_baton_t *lvb = baton;
+
+ return svn_error_trace(svn_stream_close(lvb->inner));
+}
+
+/* Gets a stream that verifies on reads that the inner stream is exactly
+ of the specified length */
+static svn_stream_t *
+get_verify_length_stream(svn_stream_t *inner,
+ svn_filesize_t expected_size,
+ apr_pool_t *result_pool)
+{
+ struct length_verify_baton_t *lvb = apr_palloc(result_pool, sizeof(*lvb));
+ svn_stream_t *len_stream = svn_stream_create(lvb, result_pool);
+
+ lvb->inner = inner;
+ lvb->remaining = expected_size;
+
+ svn_stream_set_read2(len_stream, NULL /* only full read support */,
+ read_handler_length_verify);
+ svn_stream_set_close(len_stream, close_handler_length_verify);
+
+ return len_stream;
+}
+
+svn_stream_t *
+svn_diff_get_binary_diff_original_stream(const svn_diff_binary_patch_t *bpatch,
+ apr_pool_t *result_pool)
+{
+ svn_stream_t *s = get_base85_data_stream(bpatch->apr_file, bpatch->src_start,
+ bpatch->src_end, result_pool);
+
+ s = svn_stream_compressed(s, result_pool);
+
+ /* ### If we (ever) want to support the DELTA format, then we should hook the
+ undelta handling here */
+
+ return get_verify_length_stream(s, bpatch->src_filesize, result_pool);
+}
+
+svn_stream_t *
+svn_diff_get_binary_diff_result_stream(const svn_diff_binary_patch_t *bpatch,
+ apr_pool_t *result_pool)
+{
+ svn_stream_t *s = get_base85_data_stream(bpatch->apr_file, bpatch->dst_start,
+ bpatch->dst_end, result_pool);
+
+ s = svn_stream_compressed(s, result_pool);
+
+ /* ### If we (ever) want to support the DELTA format, then we should hook the
+ undelta handling here */
+
+ return get_verify_length_stream(s, bpatch->dst_filesize, result_pool);
+}
+
/* Try to parse a positive number from a decimal number encoded
* in the string NUMBER. Return parsed number in OFFSET, and return
* TRUE if parsing was successful. */
@@ -297,7 +631,8 @@ parse_hunk_header(const char *header, sv
* Leading unidiff symbols ('+', '-', and ' ') are removed from the line,
* Any lines commencing with the VERBOTEN character are discarded.
* VERBOTEN should be '+' or '-', depending on which form of hunk text
- * is being read.
+ * is being read. NO_FINAL_EOL declares if the hunk contains a no final
+ * EOL marker.
*
* All other parameters are as in svn_diff_hunk_readline_original_text()
* and svn_diff_hunk_readline_modified_text().
@@ -309,6 +644,7 @@ hunk_readline_original_or_modified(apr_f
const char **eol,
svn_boolean_t *eof,
char verboten,
+ svn_boolean_t no_final_eol,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
@@ -316,13 +652,16 @@ hunk_readline_original_or_modified(apr_f
svn_boolean_t filtered;
apr_off_t pos;
svn_stringbuf_t *str;
+ const char *eol_p;
+
+ if (!eol)
+ eol = &eol_p;
if (range->current >= range->end)
{
/* We're past the range. Indicate that no bytes can be read. */
*eof = TRUE;
- if (eol)
- *eol = NULL;
+ *eol = NULL;
*stringbuf = svn_stringbuf_create_empty(result_pool);
return SVN_NO_ERROR;
}
@@ -345,6 +684,7 @@ hunk_readline_original_or_modified(apr_f
{
/* EOF, return an empty string. */
*stringbuf = svn_stringbuf_create_ensure(0, result_pool);
+ *eol = NULL;
}
else if (str->data[0] == '+' || str->data[0] == '-' || str->data[0] == ' ')
{
@@ -353,10 +693,34 @@ hunk_readline_original_or_modified(apr_f
}
else
{
- /* Return the line as-is. */
+ /* Return the line as-is. Handle as a chopped leading spaces */
*stringbuf = svn_stringbuf_dup(str, result_pool);
}
+ if (!filtered && *eof && !*eol && !no_final_eol && *str->data)
+ {
+ /* Ok, we miss a final EOL in the patch file, but didn't see a
+ no eol marker line.
+
+ We should report that we had an EOL or the patch code will
+ misbehave (and it knows nothing about no eol markers) */
+
+ if (eol != &eol_p)
+ {
+ apr_off_t start = 0;
+
+ SVN_ERR(svn_io_file_seek(file, APR_SET, &start, scratch_pool));
+
+ SVN_ERR(svn_io_file_readline(file, &str, eol, NULL, APR_SIZE_MAX,
+ scratch_pool, scratch_pool));
+
+ /* Every patch file that has hunks has at least one EOL*/
+ SVN_ERR_ASSERT(*eol != NULL);
+ }
+
+ *eof = FALSE;
+ /* Fall through to seek back to the right location */
+ }
SVN_ERR(svn_io_file_seek(file, APR_SET, &pos, scratch_pool));
return SVN_NO_ERROR;
@@ -377,6 +741,9 @@ svn_diff_hunk_readline_original_text(svn
&hunk->original_text_range,
stringbuf, eol, eof,
hunk->patch->reverse ? '-' : '+',
+ hunk->patch->reverse
+ ? hunk->modified_no_final_eol
+ : hunk->original_no_final_eol,
result_pool, scratch_pool));
}
@@ -395,6 +762,9 @@ svn_diff_hunk_readline_modified_text(svn
&hunk->modified_text_range,
stringbuf, eol, eof,
hunk->patch->reverse ? '+' : '-',
+ hunk->patch->reverse
+ ? hunk->original_no_final_eol
+ : hunk->modified_no_final_eol,
result_pool, scratch_pool));
}
@@ -409,13 +779,16 @@ svn_diff_hunk_readline_diff_text(svn_dif
svn_stringbuf_t *line;
apr_size_t max_len;
apr_off_t pos;
+ const char *eol_p;
+
+ if (!eol)
+ eol = &eol_p;
if (hunk->diff_text_range.current >= hunk->diff_text_range.end)
{
/* We're past the range. Indicate that no bytes can be read. */
*eof = TRUE;
- if (eol)
- *eol = NULL;
+ *eol = NULL;
*stringbuf = svn_stringbuf_create_empty(result_pool);
return SVN_NO_ERROR;
}
@@ -431,6 +804,37 @@ svn_diff_hunk_readline_diff_text(svn_dif
hunk->diff_text_range.current = 0;
SVN_ERR(svn_io_file_seek(hunk->apr_file, APR_CUR,
&hunk->diff_text_range.current, scratch_pool));
+
+ if (*eof && !*eol && *line->data)
+ {
+ /* Ok, we miss a final EOL in the patch file, but didn't see a
+ no eol marker line.
+
+ We should report that we had an EOL or the patch code will
+ misbehave (and it knows nothing about no eol markers) */
+
+ if (eol != &eol_p)
+ {
+ /* Lets pick the first eol we find in our patch file */
+ apr_off_t start = 0;
+ svn_stringbuf_t *str;
+
+ SVN_ERR(svn_io_file_seek(hunk->apr_file, APR_SET, &start,
+ scratch_pool));
+
+ SVN_ERR(svn_io_file_readline(hunk->apr_file, &str, eol, NULL,
+ APR_SIZE_MAX,
+ scratch_pool, scratch_pool));
+
+ /* Every patch file that has hunks has at least one EOL*/
+ SVN_ERR_ASSERT(*eol != NULL);
+ }
+
+ *eof = FALSE;
+
+ /* Fall through to seek back to the right location */
+ }
+
SVN_ERR(svn_io_file_seek(hunk->apr_file, APR_SET, &pos, scratch_pool));
if (hunk->patch->reverse)
@@ -637,6 +1041,8 @@ parse_next_hunk(svn_diff_hunk_t **hunk,
apr_off_t start, end;
apr_off_t original_end;
apr_off_t modified_end;
+ svn_boolean_t original_no_final_eol = FALSE;
+ svn_boolean_t modified_no_final_eol = FALSE;
svn_linenum_t original_lines;
svn_linenum_t modified_lines;
svn_linenum_t leading_context;
@@ -734,6 +1140,11 @@ parse_next_hunk(svn_diff_hunk_t **hunk,
SVN_ERR(svn_io_file_seek(apr_file, APR_SET, &pos, iterpool));
}
+ /* Set for the type and context by using != the other type */
+ if (last_line_type != modified_line)
+ original_no_final_eol = TRUE;
+ if (last_line_type != original_line)
+ modified_no_final_eol = TRUE;
continue;
}
@@ -861,14 +1272,16 @@ parse_next_hunk(svn_diff_hunk_t **hunk,
SVN_ERR(parse_prop_name(prop_name, line->data, "Added: ",
result_pool));
if (*prop_name)
- *prop_operation = svn_diff_op_added;
+ *prop_operation = (patch->reverse ? svn_diff_op_deleted
+ : svn_diff_op_added);
}
else if (starts_with(line->data, "Deleted: "))
{
SVN_ERR(parse_prop_name(prop_name, line->data, "Deleted: ",
result_pool));
if (*prop_name)
- *prop_operation = svn_diff_op_deleted;
+ *prop_operation = (patch->reverse ? svn_diff_op_added
+ : svn_diff_op_deleted);
}
else if (starts_with(line->data, "Modified: "))
{
@@ -909,6 +1322,8 @@ parse_next_hunk(svn_diff_hunk_t **hunk,
(*hunk)->modified_text_range.start = start;
(*hunk)->modified_text_range.current = start;
(*hunk)->modified_text_range.end = modified_end;
+ (*hunk)->original_no_final_eol = original_no_final_eol;
+ (*hunk)->modified_no_final_eol = modified_no_final_eol;
}
else
/* Something went wrong, just discard the result. */
@@ -940,6 +1355,8 @@ enum parse_state
state_git_tree_seen, /* a tree operation, rather than 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_git_mode_seen, /* new mode 100644 */
state_move_from_seen, /* rename from foo.c */
state_copy_from_seen, /* copy from foo.c */
state_minus_seen, /* --- foo.c */
@@ -1172,6 +1589,85 @@ 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) */));
+
+ /* Note: 0644 and 0755 are the only modes that can occur for plain files.
+ * We deliberately choose to parse only those values: we are strict in what
+ * we accept _and_ in what we produce.
+ *
+ * (Having said that, though, we could consider relaxing the parser to also
+ * map
+ * (mode & 0111) == 0000 -> svn_tristate_false
+ * (mode & 0111) == 0111 -> svn_tristate_true
+ * [anything else] -> svn_tristate_unknown
+ * .)
+ */
+
+ 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_mode_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,
@@ -1232,6 +1728,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. */
@@ -1245,6 +1745,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. */
@@ -1379,6 +1883,7 @@ parse_hunks(svn_patch_t *patch, apr_file
static svn_error_t *
parse_binary_patch(svn_patch_t *patch, apr_file_t *apr_file,
+ svn_boolean_t reverse,
apr_pool_t *result_pool, apr_pool_t *scratch_pool)
{
apr_pool_t *iterpool = svn_pool_create(scratch_pool);
@@ -1387,7 +1892,9 @@ parse_binary_patch(svn_patch_t *patch, a
svn_boolean_t eof = FALSE;
svn_diff_binary_patch_t *bpatch = apr_pcalloc(result_pool, sizeof(*bpatch));
svn_boolean_t in_blob = FALSE;
- svn_boolean_t in_dst = FALSE;
+ svn_boolean_t in_src = FALSE;
+
+ bpatch->apr_file = apr_file;
patch->operation = svn_diff_op_modified;
patch->prop_patches = apr_hash_make(result_pool);
@@ -1410,23 +1917,23 @@ parse_binary_patch(svn_patch_t *patch, a
char c = line->data[0];
/* 66 = len byte + (52/4*5) chars */
- if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')
+ if (((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'))
&& line->len <= 66
&& !strchr(line->data, ':')
&& !strchr(line->data, ' '))
{
/* One more blop line */
- if (in_dst)
- bpatch->dst_end = pos;
- else
+ if (in_src)
bpatch->src_end = pos;
+ else
+ bpatch->dst_end = pos;
}
else if (svn_stringbuf_first_non_whitespace(line) < line->len
- && !(in_dst && bpatch->dst_start < last_line))
+ && !(in_src && bpatch->src_start < last_line))
{
break; /* Bad patch */
}
- else if (in_dst)
+ else if (in_src)
{
patch->binary_patch = bpatch; /* SUCCESS! */
break;
@@ -1434,7 +1941,7 @@ parse_binary_patch(svn_patch_t *patch, a
else
{
in_blob = FALSE;
- in_dst = TRUE;
+ in_src = TRUE;
}
}
else if (starts_with(line->data, "literal "))
@@ -1450,15 +1957,15 @@ parse_binary_patch(svn_patch_t *patch, a
break;
}
- if (in_dst)
+ if (in_src)
{
- bpatch->dst_start = pos;
- bpatch->dst_filesize = expanded_size;
+ bpatch->src_start = pos;
+ bpatch->src_filesize = expanded_size;
}
else
{
- bpatch->src_start = pos;
- bpatch->src_filesize = expanded_size;
+ bpatch->dst_start = pos;
+ bpatch->dst_filesize = expanded_size;
}
in_blob = TRUE;
}
@@ -1471,12 +1978,28 @@ parse_binary_patch(svn_patch_t *patch, a
/* Rewind to the start of the line just read, so subsequent calls
* don't end up skipping the line. It may contain a patch or hunk header.*/
SVN_ERR(svn_io_file_seek(apr_file, APR_SET, &last_line, scratch_pool));
- else if (in_dst
- && ((bpatch->dst_end > bpatch->dst_start) || !bpatch->dst_filesize))
+ else if (in_src
+ && ((bpatch->src_end > bpatch->src_start) || !bpatch->src_filesize))
{
patch->binary_patch = bpatch; /* SUCCESS */
}
+ /* Reverse patch if requested */
+ if (reverse && patch->binary_patch)
+ {
+ apr_off_t tmp_start = bpatch->src_start;
+ apr_off_t tmp_end = bpatch->src_end;
+ svn_filesize_t tmp_filesize = bpatch->src_filesize;
+
+ bpatch->src_start = bpatch->dst_start;
+ bpatch->src_end = bpatch->dst_end;
+ bpatch->src_filesize = bpatch->dst_filesize;
+
+ bpatch->dst_start = tmp_start;
+ bpatch->dst_end = tmp_end;
+ bpatch->dst_filesize = tmp_filesize;
+ }
+
return SVN_NO_ERROR;
}
@@ -1489,15 +2012,22 @@ static struct transition transitions[] =
{"diff --git", state_start, git_start},
{"--- a/", state_git_diff_seen, git_minus},
+ {"--- a/", state_git_mode_seen, git_minus},
{"--- a/", state_git_tree_seen, git_minus},
+ {"--- /dev/null", state_git_mode_seen, git_minus},
{"--- /dev/null", state_git_tree_seen, git_minus},
{"+++ 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 from ", state_git_mode_seen, git_move_from},
{"rename to ", state_move_from_seen, git_move_to},
{"copy from ", state_git_diff_seen, git_copy_from},
+ {"copy from ", state_git_mode_seen, git_copy_from},
{"copy to ", state_copy_from_seen, git_copy_to},
{"new file ", state_git_diff_seen, git_new_file},
@@ -1505,6 +2035,7 @@ static struct transition transitions[] =
{"deleted file ", state_git_diff_seen, git_deleted_file},
{"GIT binary patch", state_git_diff_seen, binary_patch_start},
+ {"GIT binary patch", state_git_tree_seen, binary_patch_start},
};
svn_error_t *
@@ -1530,6 +2061,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));
@@ -1576,7 +2109,9 @@ svn_diff_parse_next_patch(svn_patch_t **
/* We have a valid diff header, yay! */
break;
}
- else if (state == state_git_tree_seen && line_after_tree_header_read)
+ else if ((state == state_git_tree_seen || state == state_git_mode_seen)
+ && line_after_tree_header_read
+ && !valid_header_line)
{
/* git patches can contain an index line after the file mode line */
if (!starts_with(line->data, "index "))
@@ -1590,7 +2125,8 @@ svn_diff_parse_next_patch(svn_patch_t **
break;
}
}
- else if (state == state_git_tree_seen)
+ else if (state == state_git_tree_seen
+ || state == state_git_mode_seen)
{
line_after_tree_header_read = TRUE;
}
@@ -1614,9 +2150,31 @@ svn_diff_parse_next_patch(svn_patch_t **
if (reverse)
{
const char *temp;
+ svn_tristate_t ts_tmp;
+
temp = patch->old_filename;
patch->old_filename = patch->new_filename;
patch->new_filename = temp;
+
+ switch (patch->operation)
+ {
+ case svn_diff_op_added:
+ patch->operation = svn_diff_op_deleted;
+ break;
+ case svn_diff_op_deleted:
+ patch->operation = svn_diff_op_added;
+ break;
+
+ /* ### case svn_diff_op_copied:
+ ### case svn_diff_op_moved:*/
+
+ case svn_diff_op_modified:
+ break; /* Stays modify */
+ }
+
+ ts_tmp = patch->old_executable_p;
+ patch->old_executable_p = patch->new_executable_p;
+ patch->new_executable_p = ts_tmp;
}
if (patch->old_filename == NULL || patch->new_filename == NULL)
@@ -1628,7 +2186,7 @@ svn_diff_parse_next_patch(svn_patch_t **
{
if (state == state_binary_patch_found)
{
- SVN_ERR(parse_binary_patch(patch, patch_file->apr_file,
+ SVN_ERR(parse_binary_patch(patch, patch_file->apr_file, reverse,
result_pool, iterpool));
/* And fall through in property parsing */
}
Modified: subversion/branches/move-tracking-2/subversion/libsvn_fs_base/lock.c
URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/libsvn_fs_base/lock.c?rev=1705712&r1=1705711&r2=1705712&view=diff
==============================================================================
--- subversion/branches/move-tracking-2/subversion/libsvn_fs_base/lock.c (original)
+++ subversion/branches/move-tracking-2/subversion/libsvn_fs_base/lock.c Mon Sep 28 16:03:14 2015
@@ -108,7 +108,7 @@ txn_body_lock(void *baton, trail_t *trai
SVN_ERR(svn_fs_base__get_path_kind(&kind, args->path, trail, trail->pool));
/* Until we implement directory locks someday, we only allow locks
- on files or non-existent paths. */
+ on files. */
if (kind == svn_node_dir)
return SVN_FS__ERR_NOT_FILE(trail->fs, args->path);
Modified: subversion/branches/move-tracking-2/subversion/libsvn_fs_fs/fs_fs.c
URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/libsvn_fs_fs/fs_fs.c?rev=1705712&r1=1705711&r2=1705712&view=diff
==============================================================================
--- subversion/branches/move-tracking-2/subversion/libsvn_fs_fs/fs_fs.c (original)
+++ subversion/branches/move-tracking-2/subversion/libsvn_fs_fs/fs_fs.c Mon Sep 28 16:03:14 2015
@@ -1485,14 +1485,27 @@ svn_fs_fs__prop_rep_equal(svn_boolean_t
&& !svn_fs_fs__id_txn_used(&rep_a->txn_id)
&& !svn_fs_fs__id_txn_used(&rep_b->txn_id))
{
- /* MD5 must be given. Having the same checksum is good enough for
- accepting the prop lists as equal. */
- *equal = memcmp(rep_a->md5_digest, rep_b->md5_digest,
- sizeof(rep_a->md5_digest)) == 0;
- return SVN_NO_ERROR;
+ /* Same representation? */
+ if ( (rep_a->revision == rep_b->revision)
+ && (rep_a->item_index == rep_b->item_index))
+ {
+ *equal = TRUE;
+ return SVN_NO_ERROR;
+ }
+
+ /* Known different content? MD5 must be given. */
+ if (memcmp(rep_a->md5_digest, rep_b->md5_digest,
+ sizeof(rep_a->md5_digest)))
+ {
+ *equal = FALSE;
+ return SVN_NO_ERROR;
+ }
}
- /* Same path in same txn? */
+ /* Same path in same txn?
+ *
+ * For committed reps, IDs cannot be the same here b/c we already know
+ * that they point to different representations. */
if (svn_fs_fs__id_eq(a->id, b->id))
{
*equal = TRUE;
Modified: subversion/branches/move-tracking-2/subversion/libsvn_fs_fs/lock.c
URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/libsvn_fs_fs/lock.c?rev=1705712&r1=1705711&r2=1705712&view=diff
==============================================================================
--- subversion/branches/move-tracking-2/subversion/libsvn_fs_fs/lock.c (original)
+++ subversion/branches/move-tracking-2/subversion/libsvn_fs_fs/lock.c Mon Sep 28 16:03:14 2015
@@ -847,7 +847,7 @@ lock_body(void *baton, apr_pool_t *pool)
apr_pool_t *iterpool = svn_pool_create(pool);
/* Until we implement directory locks someday, we only allow locks
- on files or non-existent paths. */
+ on files. */
/* Use fs->vtable->foo instead of svn_fs_foo to avoid circular
library dependencies, which are not portable. */
SVN_ERR(lb->fs->vtable->youngest_rev(&youngest, lb->fs, pool));
Modified: subversion/branches/move-tracking-2/subversion/libsvn_fs_fs/pack.c
URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/libsvn_fs_fs/pack.c?rev=1705712&r1=1705711&r2=1705712&view=diff
==============================================================================
--- subversion/branches/move-tracking-2/subversion/libsvn_fs_fs/pack.c (original)
+++ subversion/branches/move-tracking-2/subversion/libsvn_fs_fs/pack.c Mon Sep 28 16:03:14 2015
@@ -610,9 +610,6 @@ compare_dir_entries_format7(const svn_so
const svn_fs_dirent_t *lhs = (const svn_fs_dirent_t *) a->value;
const svn_fs_dirent_t *rhs = (const svn_fs_dirent_t *) b->value;
- if (lhs->kind != rhs->kind)
- return lhs->kind == svn_node_dir ? -1 : 1;
-
return strcmp(lhs->name, rhs->name);
}
@@ -810,15 +807,6 @@ compare_ref_to_item(const reference_t *
return svn_fs_fs__id_part_compare(&(*lhs_p)->from, rhs_p);
}
-/* implements compare_fn_t. Finds the DIR / FILE boundary.
- */
-static int
-compare_is_dir(const path_order_t * const * lhs_p,
- const void *unused)
-{
- return (*lhs_p)->is_dir ? -1 : 0;
-}
-
/* Look for the least significant bit set in VALUE and return the smallest
* number with the same property, i.e. the largest power of 2 that is a
* factor in VALUE. */
@@ -966,7 +954,7 @@ sort_reps(pack_context_t *context)
{
apr_pool_t *temp_pool;
const path_order_t **temp, **path_order;
- int i, count, dir_count;
+ int i, count;
/* We will later assume that there is at least one node / path.
*/
@@ -991,13 +979,8 @@ sort_reps(pack_context_t *context)
temp = apr_pcalloc(temp_pool, count * sizeof(*temp));
path_order = (void *)context->path_order->elts;
- /* Find the boundary between DIR and FILE section. */
- dir_count = svn_sort__bsearch_lower_bound(context->path_order, NULL,
- (int (*)(const void *, const void *))compare_is_dir);
-
/* Sort those sub-sections separately. */
- sort_reps_range(context, path_order, temp, 0, dir_count);
- sort_reps_range(context, path_order, temp, dir_count, count);
+ sort_reps_range(context, path_order, temp, 0, count);
/* We now know the final ordering. */
for (i = 0; i < count; ++i)
Propchange: subversion/branches/move-tracking-2/subversion/libsvn_fs_x/
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Mon Sep 28 16:03:14 2015
@@ -61,6 +61,7 @@
/subversion/branches/multi-layer-moves/subversion/libsvn_fs_x:1239019-1300930
/subversion/branches/nfc-nfd-aware-client/subversion/libsvn_fs_x:870276,870376
/subversion/branches/node_pool/subversion/libsvn_fs_x:1304828-1305388
+/subversion/branches/patch-exec/subversion/libsvn_fs_x:1692717-1705390
/subversion/branches/performance/subversion/libsvn_fs_x:979193,980118,981087,981090,981189,981194,981287,981684,981827,982043,982355,983398,983406,983430,983474,983488,983490,983760,983764,983766,983770,984927,984973,984984,985014,985037,985046,985472,985477,985482,985487-985488,985493,985497,985500,985514,985601,985603,985606,985669,985673,985695,985697,986453,986465,986485,986491-986492,986517,986521,986605,986608,986817,986832,987865,987868-987869,987872,987886-987888,987893,988319,988898,990330,990533,990535-990537,990541,990568,990572,990574-990575,990600,990759,992899,992904,992911,993127,993141,994956,995478,995507,995603,998012,998858,999098,1001413,1001417,1004291,1022668,1022670,1022676,1022715,1022719,1025660,1025672,1027193,1027203,1027206,1027214,1027227,1028077,1028092,1028094,1028104,1028107,1028111,1028354,1029038,1029042-1029043,1029054-1029055,1029062-1029063,1029078,1029080,1029090,1029092-1029093,1029111,1029151,1029158,1029229-1029230,1029232,1029335-1029336,102
9339-1029340,1029342,1029344,1030763,1030827,1031203,1031235,1032285,1032333,1033040,1033057,1033294,1035869,1035882,1039511,1043705,1053735,1056015,1066452,1067683,1067697-1078365
/subversion/branches/pin-externals/subversion/libsvn_fs_x:1643757-1659392
/subversion/branches/py-tests-as-modules/subversion/libsvn_fs_x:956579-1033052
@@ -93,4 +94,4 @@
/subversion/branches/verify-keep-going/subversion/libsvn_fs_x:1439280-1492639,1546002-1546110
/subversion/branches/wc-collate-path/subversion/libsvn_fs_x:1402685-1480384
/subversion/trunk/subversion/libsvn_fs_fs:1415133-1596500,1596567,1597414,1597989,1598273,1599140,1600872,1601633,1603485-1603487,1603499,1603605,1604128,1604188,1604413-1604414,1604416-1604417,1604421,1604442,1604700,1604717,1604720,1604726,1604755,1604794,1604802,1604824,1604836,1604844,1604902-1604903,1604911,1604925,1604933,1604947,1605059-1605060,1605064-1605065,1605068,1605071-1605073,1605075,1605123,1605188-1605189,1605191,1605197,1605444,1605633,1606132,1606142,1606144,1606514,1606526,1606528,1606551,1606554,1606564,1606598-1606599,1606656,1606658,1606662,1606744,1606840,1607085,1607572,1612407,1612810,1613339,1613872,1614611,1615348,1615351-1615352,1615356,1616338-1616339,1616613,1617586,1617688,1618138,1618151,1618153,1618226,1618641,1618653,1618662,1619068,1619358,1619413,1619769,1619774,1620602,1620909,1620912,1620928,1620930,1621275,1621635,1622931,1622937,1622942,1622946,1622959-1622960,1622963,1622987,1623007,1623368,1623373,1623377,1623379,1623381,1623398,1623402,162
4011,1624265,1624512,1626246,1626871,1626873,1626886,1627497-1627498,1627502,1627947-1627949,1627966,1628083,1628093,1628158-1628159,1628161,1628392-1628393,1628415,1628427,1628676,1628738,1628762,1628764,1629854-1629855,1629857,1629865,1629873,1629875,1629879,1630067,1630070,1631049-1631051,1631075,1631115,1631171,1631180,1631185-1631186,1631196-1631197,1631239-1631240,1631548,1631550,1631563,1631567,1631588,1631598,1632646,1632776,1632849,1632851-1632853,1632856-1632857,1632868,1632908,1632926,1633232,1633617-1633618,1634872,1634875,1634879-1634880,1634920,1636478,1636483,1636629,1636644,1637184,1637186,1637330,1637358,1637363,1637393,1639319,1639322,1639335,1639348,1639352,1639355,1639358,1639414,1639419,1639426,1639430,1639436,1639440,1639549,1640061-1640062,1640197,1640915,1640966,1641013,1643139,1643233,1645567,1646021,1646712,1646716,1647537,1647540-1647541,1647820,1647905,1648230,1648238,1648241-1648243,1648253,1648272,1648532,1648537-1648539,1648542,1648591,1648612,1653608,
1658482
-/subversion/trunk/subversion/libsvn_fs_x:1414756-1509914,1606692-1704317
+/subversion/trunk/subversion/libsvn_fs_x:1414756-1509914,1606692-1705711
Modified: subversion/branches/move-tracking-2/subversion/libsvn_fs_x/lock.c
URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/libsvn_fs_x/lock.c?rev=1705712&r1=1705711&r2=1705712&view=diff
==============================================================================
--- subversion/branches/move-tracking-2/subversion/libsvn_fs_x/lock.c (original)
+++ subversion/branches/move-tracking-2/subversion/libsvn_fs_x/lock.c Mon Sep 28 16:03:14 2015
@@ -868,7 +868,7 @@ lock_body(void *baton,
apr_pool_t *iterpool = svn_pool_create(pool);
/* Until we implement directory locks someday, we only allow locks
- on files or non-existent paths. */
+ on files. */
/* Use fs->vtable->foo instead of svn_fs_foo to avoid circular
library dependencies, which are not portable. */
SVN_ERR(lb->fs->vtable->youngest_rev(&youngest, lb->fs, pool));
Modified: subversion/branches/move-tracking-2/subversion/libsvn_ra_serf/options.c
URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/libsvn_ra_serf/options.c?rev=1705712&r1=1705711&r2=1705712&view=diff
==============================================================================
--- subversion/branches/move-tracking-2/subversion/libsvn_ra_serf/options.c (original)
+++ subversion/branches/move-tracking-2/subversion/libsvn_ra_serf/options.c Mon Sep 28 16:03:14 2015
@@ -226,6 +226,12 @@ capabilities_headers_iterator_callback(v
{
session->supports_rev_rsrc_replay = TRUE;
}
+ if (svn_cstring_match_list(SVN_DAV_NS_DAV_SVN_SVNDIFF1, vals))
+ {
+ /* Use compressed svndiff1 format for servers that properly
+ advertise this capability (Subversion 1.10 and greater). */
+ session->supports_svndiff1 = TRUE;
+ }
}
/* SVN-specific headers -- if present, server supports HTTP protocol v2 */
@@ -243,7 +249,8 @@ capabilities_headers_iterator_callback(v
apr_hash_set(session->supported_posts, "create-txn", 10, (void *)1);
}
- /* Use compressed svndiff1 format for servers that speak HTTPv2.
+ /* Use compressed svndiff1 format for servers that speak HTTPv2,
+ in addition to servers that send SVN_DAV_NS_DAV_SVN_SVNDIFF1.
Apache HTTPd + mod_dav_svn servers support svndiff1, beginning
from Subversion 1.4, but they do not advertise this capability.
Modified: subversion/branches/move-tracking-2/subversion/libsvn_ra_serf/ra_serf.h
URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/libsvn_ra_serf/ra_serf.h?rev=1705712&r1=1705711&r2=1705712&view=diff
==============================================================================
--- subversion/branches/move-tracking-2/subversion/libsvn_ra_serf/ra_serf.h (original)
+++ subversion/branches/move-tracking-2/subversion/libsvn_ra_serf/ra_serf.h Mon Sep 28 16:03:14 2015
@@ -1548,6 +1548,17 @@ svn_ra_serf__create_bucket_with_eagain(c
apr_size_t len,
serf_bucket_alloc_t *allocator);
+/* Parse a given URL_STR, fill in all supplied fields of URI
+ * structure.
+ *
+ * This function is a compatibility wrapper around apr_uri_parse().
+ * Different apr-util versions set apr_uri_t.path to either NULL or ""
+ * for root paths, and serf expects to see "/". This function always
+ * sets URI.path to "/" for these paths. */
+svn_error_t *
+svn_ra_serf__uri_parse(apr_uri_t *uri,
+ const char *url_str,
+ apr_pool_t *result_pool);
#if defined(SVN_DEBUG)
Modified: subversion/branches/move-tracking-2/subversion/libsvn_ra_serf/serf.c
URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/libsvn_ra_serf/serf.c?rev=1705712&r1=1705711&r2=1705712&view=diff
==============================================================================
--- subversion/branches/move-tracking-2/subversion/libsvn_ra_serf/serf.c (original)
+++ subversion/branches/move-tracking-2/subversion/libsvn_ra_serf/serf.c Mon Sep 28 16:03:14 2015
@@ -64,7 +64,7 @@ ra_serf_version(void)
#define RA_SERF_DESCRIPTION_VER \
N_("Module for accessing a repository via WebDAV protocol using serf.\n" \
- " - using serf %d.%d.%d")
+ " - using serf %d.%d.%d (compiled with %d.%d.%d)")
/* Implements svn_ra__vtable_t.get_description(). */
static const char *
@@ -73,7 +73,12 @@ ra_serf_get_description(apr_pool_t *pool
int major, minor, patch;
serf_lib_version(&major, &minor, &patch);
- return apr_psprintf(pool, _(RA_SERF_DESCRIPTION_VER), major, minor, patch);
+ return apr_psprintf(pool, _(RA_SERF_DESCRIPTION_VER),
+ major, minor, patch,
+ SERF_MAJOR_VERSION,
+ SERF_MINOR_VERSION,
+ SERF_PATCH_VERSION
+ );
}
/* Implements svn_ra__vtable_t.get_schemes(). */
@@ -508,19 +513,8 @@ svn_ra_serf__open(svn_ra_session_t *sess
serf_sess->pool));
- status = apr_uri_parse(serf_sess->pool, session_URL, &url);
- if (status)
- {
- return svn_error_createf(SVN_ERR_RA_ILLEGAL_URL, NULL,
- _("Illegal URL '%s'"),
- session_URL);
- }
- /* Depending the version of apr-util in use, for root paths url.path
- will be NULL or "", where serf requires "/". */
- if (url.path == NULL || url.path[0] == '\0')
- {
- url.path = apr_pstrdup(serf_sess->pool, "/");
- }
+ SVN_ERR(svn_ra_serf__uri_parse(&url, session_URL, serf_sess->pool));
+
if (!url.port)
{
url.port = apr_uri_port_of_scheme(url.scheme);
@@ -740,18 +734,15 @@ ra_serf_dup_session(svn_ra_session_t *ne
new_sess->repos_root_str = apr_pstrdup(result_pool,
new_sess->repos_root_str);
- status = apr_uri_parse(result_pool, new_sess->repos_root_str,
- &new_sess->repos_root);
- if (status)
- return svn_ra_serf__wrap_err(status, NULL);
+ SVN_ERR(svn_ra_serf__uri_parse(&new_sess->repos_root,
+ new_sess->repos_root_str,
+ result_pool));
new_sess->session_url_str = apr_pstrdup(result_pool, new_session_url);
- status = apr_uri_parse(result_pool, new_sess->session_url_str,
- &new_sess->session_url);
-
- if (status)
- return svn_ra_serf__wrap_err(status, NULL);
+ SVN_ERR(svn_ra_serf__uri_parse(&new_sess->session_url,
+ new_sess->session_url_str,
+ result_pool));
/* svn_boolean_t supports_inline_props */
/* supports_rev_rsrc_replay */
@@ -800,7 +791,6 @@ svn_ra_serf__reparent(svn_ra_session_t *
{
svn_ra_serf__session_t *session = ra_session->priv;
apr_uri_t new_url;
- apr_status_t status;
/* If it's the URL we already have, wave our hands and do nothing. */
if (strcmp(session->session_url_str, url) == 0)
@@ -822,25 +812,11 @@ svn_ra_serf__reparent(svn_ra_session_t *
"URL '%s'"), url, session->repos_root_str);
}
- status = apr_uri_parse(pool, url, &new_url);
- if (status)
- {
- return svn_error_createf(SVN_ERR_RA_ILLEGAL_URL, NULL,
- _("Illegal repository URL '%s'"), url);
- }
+ SVN_ERR(svn_ra_serf__uri_parse(&new_url, url, pool));
- /* Depending the version of apr-util in use, for root paths url.path
- will be NULL or "", where serf requires "/". */
/* ### Maybe we should use a string buffer for these strings so we
### don't allocate memory in the session on every reparent? */
- if (new_url.path == NULL || new_url.path[0] == '\0')
- {
- session->session_url.path = apr_pstrdup(session->pool, "/");
- }
- else
- {
- session->session_url.path = apr_pstrdup(session->pool, new_url.path);
- }
+ session->session_url.path = apr_pstrdup(session->pool, new_url.path);
session->session_url_str = apr_pstrdup(session->pool, url);
return SVN_NO_ERROR;
Modified: subversion/branches/move-tracking-2/subversion/libsvn_ra_serf/util.c
URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/libsvn_ra_serf/util.c?rev=1705712&r1=1705711&r2=1705712&view=diff
==============================================================================
--- subversion/branches/move-tracking-2/subversion/libsvn_ra_serf/util.c (original)
+++ subversion/branches/move-tracking-2/subversion/libsvn_ra_serf/util.c Mon Sep 28 16:03:14 2015
@@ -1951,3 +1951,29 @@ svn_ra_serf__create_handler(svn_ra_serf_
return handler;
}
+svn_error_t *
+svn_ra_serf__uri_parse(apr_uri_t *uri,
+ const char *url_str,
+ apr_pool_t *result_pool)
+{
+ apr_status_t status;
+
+ status = apr_uri_parse(result_pool, url_str, uri);
+ if (status)
+ {
+ /* Do not use returned error status in error message because currently
+ apr_uri_parse() returns APR_EGENERAL for all parsing errors. */
+ return svn_error_createf(SVN_ERR_RA_ILLEGAL_URL, NULL,
+ _("Illegal URL '%s'"),
+ url_str);
+ }
+
+ /* Depending the version of apr-util in use, for root paths uri.path
+ will be NULL or "", where serf requires "/". */
+ if (uri->path == NULL || uri->path[0] == '\0')
+ {
+ uri->path = apr_pstrdup(result_pool, "/");
+ }
+
+ return SVN_NO_ERROR;
+}
Modified: subversion/branches/move-tracking-2/subversion/libsvn_subr/auth.c
URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/libsvn_subr/auth.c?rev=1705712&r1=1705711&r2=1705712&view=diff
==============================================================================
--- subversion/branches/move-tracking-2/subversion/libsvn_subr/auth.c (original)
+++ subversion/branches/move-tracking-2/subversion/libsvn_subr/auth.c Mon Sep 28 16:03:14 2015
@@ -370,7 +370,9 @@ svn_auth_next_credentials(void **credent
if (creds != NULL)
{
/* Put the creds in the cache */
- svn_hash_sets(auth_baton->creds_cache, state->cache_key, creds);
+ svn_hash_sets(auth_baton->creds_cache,
+ apr_pstrdup(auth_baton->pool, state->cache_key),
+ creds);
break;
}
Modified: subversion/branches/move-tracking-2/subversion/libsvn_subr/win32_crashrpt.c
URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/libsvn_subr/win32_crashrpt.c?rev=1705712&r1=1705711&r2=1705712&view=diff
==============================================================================
--- subversion/branches/move-tracking-2/subversion/libsvn_subr/win32_crashrpt.c (original)
+++ subversion/branches/move-tracking-2/subversion/libsvn_subr/win32_crashrpt.c Mon Sep 28 16:03:14 2015
@@ -53,9 +53,9 @@ HANDLE dbghelp_dll = INVALID_HANDLE_VALU
#define LOGFILE_PREFIX "svn-crash-log"
#if defined(_M_IX86)
-#define FORMAT_PTR "0x%08x"
+#define FORMAT_PTR "0x%08Ix"
#elif defined(_M_X64)
-#define FORMAT_PTR "0x%016I64x"
+#define FORMAT_PTR "0x%016Ix"
#endif
/*** Code. ***/
@@ -171,7 +171,7 @@ write_module_info_callback(void *data,
MINIDUMP_MODULE_CALLBACK module = callback_input->Module;
char *buf = convert_wbcs_to_ansi(module.FullPath);
- fprintf(log_file, FORMAT_PTR, module.BaseOfImage);
+ fprintf(log_file, FORMAT_PTR, (INT_PTR)module.BaseOfImage);
fprintf(log_file, " %s", buf);
free(buf);
@@ -302,7 +302,7 @@ format_basic_type(char *buf, DWORD basic
break;
default:
sprintf(buf, "[unhandled type 0x%08x of length " FORMAT_PTR "]",
- basic_type, length);
+ basic_type, (INT_PTR)length);
break;
}
}
@@ -341,7 +341,7 @@ format_value(char *value_str, DWORD64 mo
if (ptr == 0)
sprintf(value_str, "(%s) " FORMAT_PTR,
- type_name, (DWORD_PTR *)value_addr);
+ type_name, (INT_PTR)(DWORD_PTR *)value_addr);
else if (ptr == 1)
sprintf(value_str, "(%s *) " FORMAT_PTR,
type_name, *(DWORD_PTR *)value_addr);
Modified: subversion/branches/move-tracking-2/subversion/mod_dav_svn/version.c
URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/mod_dav_svn/version.c?rev=1705712&r1=1705711&r2=1705712&view=diff
==============================================================================
--- subversion/branches/move-tracking-2/subversion/mod_dav_svn/version.c (original)
+++ subversion/branches/move-tracking-2/subversion/mod_dav_svn/version.c Mon Sep 28 16:03:14 2015
@@ -152,6 +152,7 @@ get_vsn_options(apr_pool_t *p, apr_text_
apr_text_append(p, phdr, SVN_DAV_NS_DAV_SVN_INHERITED_PROPS);
apr_text_append(p, phdr, SVN_DAV_NS_DAV_SVN_INLINE_PROPS);
apr_text_append(p, phdr, SVN_DAV_NS_DAV_SVN_REVERSE_FILE_REVS);
+ apr_text_append(p, phdr, SVN_DAV_NS_DAV_SVN_SVNDIFF1);
/* Mergeinfo is a special case: here we merely say that the server
* knows how to handle mergeinfo -- whether the repository does too
* is a separate matter.
Modified: subversion/branches/move-tracking-2/subversion/svn/notify.c
URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/svn/notify.c?rev=1705712&r1=1705711&r2=1705712&view=diff
==============================================================================
--- subversion/branches/move-tracking-2/subversion/svn/notify.c (original)
+++ subversion/branches/move-tracking-2/subversion/svn/notify.c Mon Sep 28 16:03:14 2015
@@ -415,8 +415,10 @@ notify_body(struct notify_baton *nb,
store_path(nb, nb->conflict_stats->prop_conflicts, path_local);
statchar_buf[1] = 'C';
}
+ else if (n->prop_state == svn_wc_notify_state_merged)
+ statchar_buf[1] = 'G';
else if (n->prop_state == svn_wc_notify_state_changed)
- statchar_buf[1] = 'U';
+ statchar_buf[1] = 'U';
if (statchar_buf[0] != ' ' || statchar_buf[1] != ' ')
{
Modified: subversion/branches/move-tracking-2/subversion/tests/cmdline/patch_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/tests/cmdline/patch_tests.py?rev=1705712&r1=1705711&r2=1705712&view=diff
==============================================================================
--- subversion/branches/move-tracking-2/subversion/tests/cmdline/patch_tests.py (original)
+++ subversion/branches/move-tracking-2/subversion/tests/cmdline/patch_tests.py Mon Sep 28 16:03:14 2015
@@ -2534,6 +2534,7 @@ def patch_dir_properties(sbox):
expected_output = [
' U %s\n' % wc_dir,
' C %s\n' % sbox.ospath('A/B'),
+ '> rejected hunk ## -0,0 +1,1 ## (svn:executable)\n',
] + svntest.main.summary_of_conflicts(prop_conflicts=1)
expected_disk = svntest.main.greek_state.copy()
@@ -3451,6 +3452,7 @@ def patch_add_symlink(sbox):
"Added: svn:special\n",
"## -0,0 +1 ##\n",
"+*\n",
+ "+\\ No newline at end of property\n"
]
svntest.main.file_write(patch_file_path, ''.join(unidiff_patch))
@@ -3647,7 +3649,7 @@ def patch_lacking_trailing_eol(sbox):
# Expect a newline to be appended
expected_disk = svntest.main.greek_state.copy()
- expected_disk.tweak('iota', contents=iota_contents + "Some more bytes")
+ expected_disk.tweak('iota', contents=iota_contents + "Some more bytes\n")
expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
expected_status.tweak('iota', status='M ')
@@ -4559,7 +4561,6 @@ def patch_apply_no_fuz(sbox):
if not filecmp.cmp(sbox.ospath('test.txt'), sbox.ospath('test_v2.txt')):
raise svntest.Failure("Patch result not identical")
-@XFail()
def patch_lacking_trailing_eol_on_context(sbox):
"patch file lacking trailing eol on context"
@@ -5620,7 +5621,6 @@ def patch_obstructing_symlink_traversal(
expected_output, expected_disk,
expected_status, expected_skip)
-@XFail()
def patch_binary_file(sbox):
"patch a binary file"
@@ -5637,13 +5637,13 @@ def patch_binary_file(sbox):
'===================================================================\n',
'diff --git a/iota b/iota\n',
'GIT binary patch\n',
- 'literal 25\n',
- 'ec$^E#$ShU>qLPeMg|y6^R0Z|S{E|d<JuU!m{s;*G\n',
- '\n',
'literal 48\n',
'zc$^E#$ShU>qLPeMg|y6^R0Z|S{E|d<JuZf(=9bpB_PpZ!+|-hc%)E52)STkf{{Wp*\n',
'B5)uFa\n',
'\n',
+ 'literal 25\n',
+ 'ec$^E#$ShU>qLPeMg|y6^R0Z|S{E|d<JuU!m{s;*G\n',
+ '\n',
'Property changes on: iota\n',
'___________________________________________________________________\n',
'Added: svn:mime-type\n',
@@ -5664,16 +5664,694 @@ def patch_binary_file(sbox):
expected_output = wc.State(wc_dir, {
'iota' : Item(status='UU'),
})
- expected_disk = None
+ expected_disk = svntest.main.greek_state.copy()
+ expected_disk.tweak('iota',
+ props={'svn:mime-type':'application/binary'},
+ contents =
+ 'This is the file \'iota\'.\n'
+ '\0\202\203\204\205\206\207nsomething\nelse\xFF')
expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
expected_status.tweak('iota', status='MM')
expected_skip = wc.State('', { })
svntest.actions.run_and_verify_patch(wc_dir, tmp,
expected_output, expected_disk,
+ expected_status, expected_skip,
+ [], True, True)
+
+ # Ok, now try applying it backwards
+ expected_output.tweak('iota', status='GU')
+ expected_disk = svntest.main.greek_state.copy()
+ expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
+ svntest.actions.run_and_verify_patch(wc_dir, tmp,
+ expected_output, expected_disk,
+ expected_status, expected_skip,
+ [], False, True, '--reverse-diff')
+
+def patch_delete_nodes(sbox):
+ "apply deletes via patch"
+
+ sbox.build()
+ wc_dir = sbox.wc_dir
+
+ sbox.simple_propset('A', 'B', 'A/B/E/alpha')
+ sbox.simple_append('A/mu', '\0')
+ sbox.simple_propset('svn:mime-type', 'application/nonsense', 'A/mu')
+
+ sbox.simple_commit() # r2
+ sbox.simple_update()
+
+ expected_skip = wc.State('', { })
+
+ original_status = svntest.actions.get_virginal_state(wc_dir, 2)
+ original_disk = svntest.main.greek_state.copy()
+ original_disk.tweak('A/mu',
+ props={'svn:mime-type':'application/nonsense'},
+ contents = 'This is the file \'mu\'.\n\0')
+ original_disk.tweak('A/B/E/alpha', props={'A':'B'})
+ svntest.actions.run_and_verify_status(wc_dir, original_status)
+ svntest.actions.verify_disk(wc_dir, original_disk, True)
+
+ sbox.simple_rm('A/B/E/alpha', 'A/B/E/beta', 'A/mu')
+
+ _, diff, _ = svntest.actions.run_and_verify_svn(None, [],
+ 'diff', '--git', wc_dir)
+
+ patch = sbox.get_tempname('patch')
+ svntest.main.file_write(patch, ''.join(diff))
+
+ deleted_status = original_status.copy()
+ deleted_disk = original_disk.copy()
+ deleted_disk.remove('A/B/E/alpha', 'A/B/E/beta', 'A/mu')
+ deleted_status.tweak('A/B/E/alpha', 'A/B/E/beta', 'A/mu', status='D ')
+
+
+ svntest.actions.run_and_verify_status(wc_dir, deleted_status)
+ svntest.actions.verify_disk(wc_dir, deleted_disk, True)
+
+ # And now apply the patch from the clean state
+ sbox.simple_revert('A/B/E/alpha', 'A/B/E/beta', 'A/mu')
+
+ # Expect that the hint 'empty dir? -> delete dir' deletes 'E'
+ # ### A smarter diff format might change this in a future version
+ deleted_disk.remove('A/B/E')
+ deleted_status.tweak('A/B/E', status='D ')
+ expected_output = wc.State(wc_dir, {
+ 'A/mu' : Item(status='D '),
+ 'A/B/E' : Item(status='D '),
+ 'A/B/E/beta' : Item(status='D '),
+ 'A/B/E/alpha' : Item(status='D '),
+ })
+
+ svntest.actions.run_and_verify_patch(wc_dir, patch,
+ expected_output, deleted_disk,
+ deleted_status, expected_skip,
+ [], False, True)
+
+ # And let's see if we can apply the reverse version of the patch
+ expected_output = wc.State(wc_dir, {
+ 'A/mu' : Item(status='A '),
+ 'A/B/E' : Item(status='A '),
+ 'A/B/E/beta' : Item(status='A '),
+ 'A/B/E/alpha' : Item(status='A '),
+ })
+ original_status.tweak('A/mu', status='RM') # New file
+ original_status.tweak('A/B/E', status='R ') # New dir
+ original_status.tweak('A/B/E/alpha', 'A/B/E/beta',
+ status='A ', wc_rev='-',
+ entry_status='R ', entry_rev='2')
+
+
+ svntest.actions.run_and_verify_patch(wc_dir, patch,
+ expected_output, original_disk,
+ original_status, expected_skip,
+ [], True, True, '--reverse-diff')
+
+def patch_delete_missing_eol(sbox):
+ "apply a delete missing an eol"
+
+ sbox.build(read_only = True)
+ wc_dir = sbox.wc_dir
+
+ delete_patch = [
+ "Index: A/B/E/beta\n",
+ "===================================================================\n",
+ "--- A/B/E/beta (revision 1)\n",
+ "+++ /dev/null\n",
+ "@@ -1 +0,0 @@\n",
+ "-This is the file 'beta'." # No final EOL
+ ]
+
+ patch = sbox.get_tempname('patch')
+ svntest.main.file_write(patch, ''.join(delete_patch))
+
+ expected_output = wc.State(wc_dir, {
+ 'A/B/E/beta' : Item(status='D '),
+ })
+ expected_skip = wc.State(wc_dir, {
+ })
+ expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
+ expected_status.tweak('A/B/E/beta', status='D ')
+ expected_disk = svntest.main.greek_state.copy()
+ expected_disk.remove('A/B/E/beta')
+
+ svntest.actions.run_and_verify_patch(wc_dir, patch,
+ expected_output, expected_disk,
+ expected_status, expected_skip,
+ [], False, True)
+
+ # Try again? -> Skip... Why not some already applied notification?
+ # -> There is nothing to compare to
+ expected_output = wc.State(wc_dir, {
+ })
+ expected_skip = wc.State(wc_dir, {
+ 'A/B/E/beta' : Item(verb='Skipped'),
+ })
+ svntest.actions.run_and_verify_patch(wc_dir, patch,
+ expected_output, expected_disk,
+ expected_status, expected_skip,
+ [], False, True)
+
+ # Reverse
+ expected_output = wc.State(wc_dir, {
+ 'A/B/E/beta' : Item(status='A '),
+ })
+ expected_skip = wc.State(wc_dir, {
+ })
+ expected_disk = svntest.main.greek_state.copy()
+ expected_status.tweak('A/B/E/beta', status='R ')
+ svntest.actions.run_and_verify_patch(wc_dir, patch,
+ expected_output, expected_disk,
+ expected_status, expected_skip,
+ [], False, True, '--reverse-diff')
+
+ # Try again? -> Already applied
+ expected_output = wc.State(wc_dir, {
+ 'A/B/E/beta' : Item(status='G '),
+ })
+ expected_skip = wc.State(wc_dir, {
+ })
+ svntest.actions.run_and_verify_patch(wc_dir, patch,
+ expected_output, expected_disk,
+ expected_status, expected_skip,
+ [], False, True, '--reverse-diff')
+
+def patch_final_eol(sbox):
+ "patch the final eol"
+
+ sbox.build()
+ wc_dir = sbox.wc_dir
+
+ delete_patch = [
+ 'Index: A/mu\n',
+ '===================================================================\n',
+ '--- A/mu\t(revision 1)\n',
+ '+++ A/mu\t(working copy)\n',
+ '@@ -1 +1 @@\n',
+ '-This is the file \'mu\'.\n',
+ '+This is the file \'mu\'.\n',
+ '\ No newline at end of file\n',
+ 'Index: iota\n',
+ '===================================================================\n',
+ '--- iota\t(revision 1)\n',
+ '+++ iota\t(working copy)\n',
+ '@@ -1 +1 @@\n',
+ '-This is the file \'iota\'.\n',
+ '+This is the file \'iota\'.\n',
+ '\ No newline at end of file' # Missing EOL
+ ]
+
+ patch = sbox.get_tempname('patch')
+ # We explicitly use wb here as this is the eol type added later in the test
+ svntest.main.file_write(patch, ''.join(delete_patch), mode='wb')
+
+ expected_output = wc.State(wc_dir, {
+ 'A/mu' : Item(status='U '),
+ 'iota' : Item(status='U '),
+ })
+ expected_skip = wc.State(wc_dir, {})
+ expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
+ expected_status.tweak('iota', 'A/mu', status='M ')
+ expected_disk = svntest.main.greek_state.copy()
+ expected_disk.tweak('iota', contents="This is the file 'iota'.")
+ expected_disk.tweak('A/mu', contents="This is the file 'mu'.")
+
+ svntest.actions.run_and_verify_patch(wc_dir, patch,
+ expected_output, expected_disk,
+ expected_status, expected_skip,
+ [], False, True)
+
+ # And again
+ expected_output.tweak('iota', 'A/mu', status='G ')
+ svntest.actions.run_and_verify_patch(wc_dir, patch,
+ expected_output, expected_disk,
+ expected_status, expected_skip,
+ [], False, True)
+
+ # Reverse
+ expected_disk.tweak('iota', contents="This is the file 'iota'.\n")
+ expected_disk.tweak('A/mu', contents="This is the file 'mu'.\n")
+ expected_status.tweak('iota', 'A/mu', status=' ')
+ svntest.actions.run_and_verify_patch(wc_dir, patch,
+ expected_output, expected_disk,
+ expected_status, expected_skip,
+ [], False, True, '--reverse-diff')
+
+ # And once more
+ expected_output.tweak('iota', 'A/mu', status='U ')
+ svntest.actions.run_and_verify_patch(wc_dir, patch,
+ expected_output, expected_disk,
+ expected_status, expected_skip,
+ [], False, True, '--reverse-diff')
+
+ # Change the unmodified form
+ sbox.simple_append('iota', 'This is the file \'iota\'.', truncate=True)
+ sbox.simple_append('A/mu', 'This is the file \'mu\'.', truncate=True)
+ sbox.simple_commit()
+ expected_status.tweak('iota', 'A/mu', wc_rev='2')
+
+ add_patch = [
+ 'Index: A/mu\n',
+ '===================================================================\n',
+ '--- A/mu\t(revision 2)\n',
+ '+++ A/mu\t(working copy)\n',
+ '@@ -1 +1 @@\n',
+ '-This is the file \'mu\'.\n',
+ '\ No newline at end of file\n',
+ '+This is the file \'mu\'.\n',
+ 'Index: iota\n',
+ '===================================================================\n',
+ '--- iota\t(revision 2)\n',
+ '+++ iota\t(working copy)\n',
+ '@@ -1 +1 @@\n',
+ '-This is the file \'iota\'.\n',
+ '\ No newline at end of file\n',
+ '+This is the file \'iota\'.' # Missing eol
+ ]
+
+ svntest.main.file_write(patch, ''.join(add_patch), mode='wb')
+
+ # Apply the patch
+ expected_output.tweak('iota', 'A/mu', status='U ')
+ expected_disk.tweak('iota', contents="This is the file 'iota'.\n")
+ expected_disk.tweak('A/mu', contents="This is the file 'mu'.\n")
+ expected_status.tweak('iota', 'A/mu', status='M ')
+ svntest.actions.run_and_verify_patch(wc_dir, patch,
+ expected_output, expected_disk,
+ expected_status, expected_skip,
+ [], False, True)
+
+ # And again
+ expected_output.tweak('iota', 'A/mu', status='G ')
+ svntest.actions.run_and_verify_patch(wc_dir, patch,
+ expected_output, expected_disk,
+ expected_status, expected_skip,
+ [], False, True)
+
+ # And in reverse
+ expected_disk.tweak('iota', contents="This is the file 'iota'.")
+ expected_disk.tweak('A/mu', contents="This is the file 'mu'.")
+ expected_status.tweak('iota', 'A/mu', status=' ')
+ svntest.actions.run_and_verify_patch(wc_dir, patch,
+ expected_output, expected_disk,
+ expected_status, expected_skip,
+ [], False, True, '--reverse-diff')
+
+ # And again
+ expected_output.tweak('iota', 'A/mu', status='U ')
+ svntest.actions.run_and_verify_patch(wc_dir, patch,
+ expected_output, expected_disk,
+ expected_status, expected_skip,
+ [], False, True, '--reverse-diff')
+
+def patch_adds_executability_nocontents(sbox):
+ """patch adds svn:executable, without contents"""
+
+ sbox.build(read_only=True)
+ wc_dir = sbox.wc_dir
+
+ unidiff_patch = (
+ "diff --git a/iota b/iota\n"
+ "old mode 100644\n"
+ "new mode 100755\n"
+ )
+ patch_file_path = make_patch_path(sbox)
+ svntest.main.file_write(patch_file_path, unidiff_patch)
+
+ expected_output = wc.State(wc_dir, {
+ 'iota' : Item(status=' U')
+ })
+ expected_disk = svntest.main.greek_state.copy()
+ # "*" is SVN_PROP_EXECUTABLE_VALUE aka SVN_PROP_BOOLEAN_TRUE
+ expected_disk.tweak('iota', props={'svn:executable': '*'})
+
+ expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
+ expected_status.tweak('iota', status=' M')
+
+ expected_skip = wc.State(wc_dir, { })
+
+ svntest.actions.run_and_verify_patch(wc_dir, os.path.abspath(patch_file_path),
+ expected_output, expected_disk,
+ expected_status, expected_skip,
+ check_props=True)
+
+ # And try it again
+ # This may produce different output but must have the same result
+ svntest.actions.run_and_verify_patch(wc_dir, os.path.abspath(patch_file_path),
+ expected_output, expected_disk,
+ expected_status, expected_skip,
+ check_props=True)
+
+ # And then try it in reverse
+ expected_disk.tweak('iota', props={})
+ expected_status.tweak('iota', status=' ')
+ svntest.actions.run_and_verify_patch(wc_dir, patch_file_path,
+ expected_output, expected_disk,
+ expected_status, expected_skip,
+ [], True, True, '--reverse-diff')
+
+ # And try it again
+ # This may produce different output but must have the same result
+ svntest.actions.run_and_verify_patch(wc_dir, patch_file_path,
+ expected_output, expected_disk,
+ expected_status, expected_skip,
+ [], True, True, '--reverse-diff')
+
+@XFail()
+def patch_adds_executability_nocontents2(sbox):
+ "patch adds svn:executable, without contents 2"
+
+ sbox.build(read_only=True)
+ wc_dir = sbox.wc_dir
+
+ unidiff_patch = (
+ "diff --git a/new b/new\n"
+ "old mode 100644\n"
+ "new mode 100755\n"
+ )
+ patch_file_path = make_patch_path(sbox)
+ svntest.main.file_write(patch_file_path, unidiff_patch)
+
+ expected_output = wc.State(wc_dir, {
+ })
+ expected_disk = svntest.main.greek_state.copy()
+ expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
+ expected_status.tweak('iota', status=' M')
+
+ expected_skip = wc.State(wc_dir, {
+ 'new' : Item(verb='Skipped')
+ })
+
+ # This creates 'new', while a skip or reject is expected
+ svntest.actions.run_and_verify_patch(wc_dir, patch_file_path,
+ expected_output, expected_disk,
expected_status, expected_skip)
+def patch_adds_executability_yescontents(sbox):
+ """patch adds svn:executable, with contents"""
+
+ sbox.build(read_only=True)
+ wc_dir = sbox.wc_dir
+
+ mu_new_contents = (
+ "This is the file 'mu'.\n"
+ "with text mods too\n"
+ )
+
+ unidiff_patch = (
+ "diff --git a/A/mu b/A/mu\n"
+ "old mode 100644\n"
+ "new mode 100755\n"
+ "index 8a0f01c..dfad3ac\n"
+ "--- a/A/mu\n"
+ "+++ b/A/mu\n"
+ "@@ -1 +1,2 @@\n"
+ " This is the file 'mu'.\n"
+ "+with text mods too\n"
+ )
+ patch_file_path = make_patch_path(sbox)
+ svntest.main.file_write(patch_file_path, unidiff_patch)
+
+ expected_output = [
+ 'UU %s\n' % sbox.ospath('A/mu'),
+ ]
+ expected_disk = svntest.main.greek_state.copy()
+ # "*" is SVN_PROP_EXECUTABLE_VALUE aka SVN_PROP_BOOLEAN_TRUE
+ expected_disk.tweak('A/mu', props={'svn:executable': '*'})
+ expected_disk.tweak('A/mu', contents=mu_new_contents)
+
+ expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
+ expected_status.tweak('A/mu', status='MM')
+
+ expected_skip = wc.State('', { })
+
+ svntest.actions.run_and_verify_patch(wc_dir, os.path.abspath(patch_file_path),
+ expected_output, expected_disk,
+ expected_status, expected_skip,
+ check_props=True)
+
+def patch_deletes_executability(sbox):
+ """patch deletes svn:executable"""
+
+ sbox.build(read_only=True)
+ wc_dir = sbox.wc_dir
+
+ ## Set up the basic state.
+ sbox.simple_propset('svn:executable', 'yes', 'iota')
+ #sbox.simple_commit(target='iota', message="Make 'iota' executable.")
+
+ unidiff_patch = (
+ "diff --git a/iota b/iota\n"
+ "old mode 100755\n"
+ "new mode 100644\n"
+ )
+ patch_file_path = make_patch_path(sbox)
+ svntest.main.file_write(patch_file_path, unidiff_patch)
+
+ expected_output = [
+ ' U %s\n' % sbox.ospath('iota'),
+ ]
+ expected_disk = svntest.main.greek_state.copy()
+ expected_disk.tweak('iota') # props=None by default
+
+ expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
+ expected_status.tweak('iota', status=' ')
+
+ expected_skip = wc.State('', { })
+
+ svntest.actions.run_and_verify_patch(wc_dir, os.path.abspath(patch_file_path),
+ expected_output, expected_disk,
+ expected_status, expected_skip,
+ check_props=True)
+
+def patch_ambiguous_executability_contradiction(sbox):
+ """patch ambiguous svn:executable, bad"""
+
+ sbox.build(read_only=True)
+ wc_dir = sbox.wc_dir
+
+ unidiff_patch = (
+ "Index: iota\n"
+ "===================================================================\n"
+ "diff --git a/iota b/iota\n"
+ "old mode 100755\n"
+ "new mode 100644\n"
+ "Property changes on: iota\n"
+ "-------------------------------------------------------------------\n"
+ "Added: svn:executable\n"
+ "## -0,0 +1 ##\n"
+ "+*\n"
+ )
+ patch_file_path = make_patch_path(sbox)
+ svntest.main.file_write(patch_file_path, unidiff_patch)
+
+ expected_output = []
+
+ expected_disk = svntest.main.greek_state.copy()
+
+ expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
+
+ expected_skip = wc.State('', { })
+
+ error_re_string = r'.*Invalid patch:.*contradicting.*mode.*svn:executable'
+ svntest.actions.run_and_verify_patch(wc_dir, os.path.abspath(patch_file_path),
+ expected_output, expected_disk,
+ expected_status, expected_skip,
+ error_re_string=error_re_string,
+ check_props=True)
+
+def patch_ambiguous_executability_consistent(sbox):
+ """patch ambiguous svn:executable, good"""
+
+ sbox.build(read_only=True)
+ wc_dir = sbox.wc_dir
+
+ unidiff_patch = (
+ "Index: iota\n"
+ "===================================================================\n"
+ "diff --git a/iota b/iota\n"
+ "old mode 100644\n"
+ "new mode 100755\n"
+ "Property changes on: iota\n"
+ "-------------------------------------------------------------------\n"
+ "Added: svn:executable\n"
+ "## -0,0 +1 ##\n"
+ "+*\n"
+ )
+ patch_file_path = make_patch_path(sbox)
+ svntest.main.file_write(patch_file_path, unidiff_patch)
+
+ expected_output = [
+ ' U %s\n' % sbox.ospath('iota'),
+ ]
+
+ expected_disk = svntest.main.greek_state.copy()
+ expected_disk.tweak('iota', props={'svn:executable': '*'})
+
+ expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
+ expected_status.tweak('iota', status=' M')
+
+ expected_skip = wc.State('', { })
+
+ svntest.actions.run_and_verify_patch(wc_dir, os.path.abspath(patch_file_path),
+ expected_output, expected_disk,
+ expected_status, expected_skip,
+ error_re_string=None,
+ check_props=True)
+
+def patch_prop_madness(sbox):
+ "patch property madness"
+
+ sbox.build()
+ wc_dir = sbox.wc_dir
+
+ sbox.simple_propset('mod_s', 'value\n',
+ 'iota', 'A/mu')
+
+ sbox.simple_propset('mod_s_n', 'no-eol',
+ 'iota', 'A/mu')
+
+ sbox.simple_propset('mod_l', 'this\nis\na\nvery\nvery\nlong\nvalue.\n',
+ 'iota', 'A/mu')
+
+ sbox.simple_propset('mod_l_n', 'this\nis\na\nvery\nvery\nlong\nvalue.\n'
+ 'without\neol', # No eol at end
+ 'iota', 'A/mu')
+
+ sbox.simple_propset('del', 'value\n',
+ 'iota', 'A/mu')
+
+ sbox.simple_propset('del_n', 'no-eol',
+ 'iota', 'A/mu')
+
+ sbox.simple_commit()
+
+ sbox.simple_propset('mod_s', 'other\n',
+ 'iota', 'A/mu')
+
+ sbox.simple_propset('mod_s_n', 'still no eol',
+ 'iota', 'A/mu')
+
+ sbox.simple_propset('mod_l', 'this\nis\na\nsomewhat\nlong\nvalue.\n',
+ 'iota', 'A/mu')
+
+ sbox.simple_propset('mod_l_n', 'this\nis\na\nanother\n..\nlong\nvalue.\n'
+ 'without\neol', # No eol at end
+ 'iota', 'A/mu')
+
+ sbox.simple_propdel('del', 'iota', 'A/mu')
+
+ sbox.simple_propdel('del_n', 'iota', 'A/mu')
+
+ sbox.simple_propset('add_s', 'new-value\n',
+ 'iota', 'A/mu')
+
+ sbox.simple_propset('add_s_n', 'new other no eol',
+ 'iota', 'A/mu')
+
+ sbox.simple_propset('add_l', 'this\nis\nsomething\n',
+ 'iota', 'A/mu')
+
+ sbox.simple_propset('add_l_n', 'this\nhas\nno\neol', # No eol at end
+ 'iota', 'A/mu')
+
+ _, output, _ = svntest.actions.run_and_verify_svn(None, [],
+ 'diff', wc_dir)
+
+ expected_disk = svntest.main.greek_state.copy()
+ expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
+
+ new_props = {
+ 'mod_s' : 'other\n',
+ 'mod_s_n' : 'still no eol',
+ 'mod_l' : 'this\nis\na\nsomewhat\nlong\nvalue.\n',
+ 'mod_l_n' : 'this\nis\na\nanother\n..\nlong\nvalue.\nwithout\neol',
+ 'add_s' : 'new-value\n',
+ 'add_s_n' : 'new other no eol',
+ 'add_l' : 'this\nis\nsomething\n',
+ 'add_l_n' : 'this\nhas\nno\neol'
+ }
+
+ expected_status.tweak('iota', 'A/mu', status=' M', wc_rev='2')
+ expected_disk.tweak('iota', 'A/mu', props=new_props)
+
+ svntest.actions.verify_disk(wc_dir, expected_disk, True)
+ #svntest.actions.run_and_verify_status(wc_dir, expected_status)
+
+ svntest.actions.run_and_verify_svn(None, [],
+ 'revert', wc_dir, '-R')
+
+ patch = sbox.get_tempname('patch')
+ svntest.main.file_write(patch, ''.join(output), mode='wb')
+
+ expected_output = wc.State(wc_dir, {
+ 'A/mu' : Item(status=' U'),
+ 'iota' : Item(status=' U'),
+ })
+ expected_skip= wc.State(wc_dir, {
+ })
+
+ strip_count = wc_dir.count(os.path.sep)+1
+
+ # Patch once
+ svntest.actions.run_and_verify_patch(wc_dir, patch,
+ expected_output, expected_disk,
+ expected_status, expected_skip,
+ [], True, True,
+ '--strip', strip_count)
+
+ # Patch again
+ expected_output.tweak('A/mu', 'iota', status=' G')
+ svntest.actions.run_and_verify_patch(wc_dir, patch,
+ expected_output, expected_disk,
+ expected_status, expected_skip,
+ [], True, True,
+ '--strip', strip_count)
+
+ # Reverse
+ expected_output.tweak('A/mu', 'iota', status=' U')
+ props = {
+ 'mod_l_n' : 'this\nis\na\nvery\nvery\nlong\nvalue.\nwithout\neol',
+ 'mod_l' : 'this\nis\na\nvery\nvery\nlong\nvalue.\n',
+ 'mod_s' : 'value\n',
+ 'mod_s_n' : 'no-eol',
+ 'del' : 'value\n',
+ 'del_n' : 'no-eol',
+ }
+ expected_disk.tweak('A/mu', 'iota', props=props)
+ expected_status.tweak('A/mu', 'iota', status=' ')
+ svntest.actions.run_and_verify_patch(wc_dir, patch,
+ expected_output, expected_disk,
+ expected_status, expected_skip,
+ [], True, True,
+ '--reverse-diff',
+ '--strip', strip_count)
+
+ # And repeat
+ expected_output.tweak('A/mu', 'iota', status=' G')
+ svntest.actions.run_and_verify_patch(wc_dir, patch,
+ expected_output, expected_disk,
+ expected_status, expected_skip,
+ [], True, True,
+ '--reverse-diff',
+ '--strip', strip_count)
+
+ # Ok, and now introduce some conflicts
+
+ sbox.simple_propset('del', 'value', 'iota') # Wrong EOL
+ sbox.simple_propset('del', 'waarde', 'A/mu') # Wrong EOL+value
+
+ sbox.simple_propset('del_n', 'no-eol\n', 'iota') # Wrong EOL
+ sbox.simple_propset('del_n', 'regeleinde\n', 'iota') # Wrong EOL+value
+
+ expected_output.tweak('A/mu', 'iota', status=' C')
+ svntest.actions.run_and_verify_patch(wc_dir, patch,
+ expected_output, expected_disk,
+ expected_status, expected_skip,
+ [], True, True,
+ '--strip', strip_count)
+
########################################################################
#Run the tests
@@ -5736,6 +6414,16 @@ test_list = [ None,
patch_symlink_traversal,
patch_obstructing_symlink_traversal,
patch_binary_file,
+ patch_delete_nodes,
+ patch_delete_missing_eol,
+ patch_final_eol,
+ patch_adds_executability_nocontents,
+ patch_adds_executability_nocontents2,
+ patch_adds_executability_yescontents,
+ patch_deletes_executability,
+ patch_ambiguous_executability_contradiction,
+ patch_ambiguous_executability_consistent,
+ patch_prop_madness,
]
if __name__ == '__main__':
Modified: subversion/branches/move-tracking-2/subversion/tests/cmdline/svntest/tree.py
URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/tests/cmdline/svntest/tree.py?rev=1705712&r1=1705711&r2=1705712&view=diff
==============================================================================
--- subversion/branches/move-tracking-2/subversion/tests/cmdline/svntest/tree.py (original)
+++ subversion/branches/move-tracking-2/subversion/tests/cmdline/svntest/tree.py Mon Sep 28 16:03:14 2015
@@ -285,16 +285,7 @@ class SVNTreeNode:
if self.props:
if comma:
line += ", "
- line += "props={"
- comma = False
-
- for name in self.props:
- if comma:
- line += ", "
- line += "'%s':'%s'" % (name, self.props[name])
- comma = True
-
- line += "}"
+ line += ("props=%s" % self.props)
comma = True
for name in self.atts:
Modified: subversion/branches/move-tracking-2/subversion/tests/libsvn_client/client-test.c
URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/tests/libsvn_client/client-test.c?rev=1705712&r1=1705711&r2=1705712&view=diff
==============================================================================
--- subversion/branches/move-tracking-2/subversion/tests/libsvn_client/client-test.c (original)
+++ subversion/branches/move-tracking-2/subversion/tests/libsvn_client/client-test.c Mon Sep 28 16:03:14 2015
@@ -740,14 +740,14 @@ test_foreign_repos_copy(const svn_test_o
wc_path = svn_test_data_path("test-foreign-repos-copy", pool);
- wc_path = svn_dirent_join(wc_path, "foreign-wc", pool);
-
/* Remove old test data from the previous run */
SVN_ERR(svn_io_remove_dir2(wc_path, TRUE, NULL, NULL, pool));
SVN_ERR(svn_io_make_dir_recursively(wc_path, pool));
svn_test_add_dir_cleanup(wc_path);
+ wc_path = svn_dirent_join(wc_path, "foreign-wc", pool);
+
rev.kind = svn_opt_revision_head;
peg_rev.kind = svn_opt_revision_unspecified;
SVN_ERR(svn_client_create_context(&ctx, pool));
@@ -953,7 +953,7 @@ test_remote_only_status(const svn_test_o
/* Check out a sparse root @r1 of the repository */
wc_path = svn_test_data_path("test-remote-only-status-wc", pool);
- /*svn_test_add_dir_cleanup(wc_path);*/
+ svn_test_add_dir_cleanup(wc_path);
SVN_ERR(svn_io_remove_dir2(wc_path, TRUE, NULL, NULL, pool));
rev.kind = svn_opt_revision_number;