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 [1/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...
Author: julianfoad
Date: Mon Sep 28 16:03:14 2015
New Revision: 1705712
URL: http://svn.apache.org/viewvc?rev=1705712&view=rev
Log:
On the 'move-tracking-2' branch: catch up to trunk@1705711.
Modified:
subversion/branches/move-tracking-2/ (props changed)
subversion/branches/move-tracking-2/subversion/ (props changed)
subversion/branches/move-tracking-2/subversion/include/private/svn_diff_private.h
subversion/branches/move-tracking-2/subversion/include/svn_dav.h
subversion/branches/move-tracking-2/subversion/include/svn_diff.h
subversion/branches/move-tracking-2/subversion/include/svn_error_codes.h
subversion/branches/move-tracking-2/subversion/libsvn_client/client.h
subversion/branches/move-tracking-2/subversion/libsvn_client/patch.c
subversion/branches/move-tracking-2/subversion/libsvn_diff/binary_diff.c
subversion/branches/move-tracking-2/subversion/libsvn_diff/diff.h
subversion/branches/move-tracking-2/subversion/libsvn_diff/parse-diff.c
subversion/branches/move-tracking-2/subversion/libsvn_fs_base/lock.c
subversion/branches/move-tracking-2/subversion/libsvn_fs_fs/fs_fs.c
subversion/branches/move-tracking-2/subversion/libsvn_fs_fs/lock.c
subversion/branches/move-tracking-2/subversion/libsvn_fs_fs/pack.c
subversion/branches/move-tracking-2/subversion/libsvn_fs_x/ (props changed)
subversion/branches/move-tracking-2/subversion/libsvn_fs_x/lock.c
subversion/branches/move-tracking-2/subversion/libsvn_ra_serf/options.c
subversion/branches/move-tracking-2/subversion/libsvn_ra_serf/ra_serf.h
subversion/branches/move-tracking-2/subversion/libsvn_ra_serf/serf.c
subversion/branches/move-tracking-2/subversion/libsvn_ra_serf/util.c
subversion/branches/move-tracking-2/subversion/libsvn_subr/auth.c
subversion/branches/move-tracking-2/subversion/libsvn_subr/win32_crashrpt.c
subversion/branches/move-tracking-2/subversion/mod_dav_svn/version.c
subversion/branches/move-tracking-2/subversion/svn/notify.c
subversion/branches/move-tracking-2/subversion/tests/cmdline/patch_tests.py
subversion/branches/move-tracking-2/subversion/tests/cmdline/svntest/tree.py
subversion/branches/move-tracking-2/subversion/tests/libsvn_client/client-test.c
subversion/branches/move-tracking-2/subversion/tests/libsvn_diff/parse-diff-test.c
subversion/branches/move-tracking-2/tools/ (props changed)
subversion/branches/move-tracking-2/tools/dist/backport/merger.py
subversion/branches/move-tracking-2/tools/dist/backport/status.py
Propchange: subversion/branches/move-tracking-2/
------------------------------------------------------------------------------
--- bugtraq:logregex (original)
+++ bugtraq:logregex Mon Sep 28 16:03:14 2015
@@ -1,2 +1,2 @@
-[Ii]ssues?:?(\s*(,|and)?\s*#\d+)+
+([Ii]ssues?:?(\s*(,|and)?\s*[#]?\d+)+)|(\bSVN-(\d+)\b)
(\d+)
Propchange: subversion/branches/move-tracking-2/
------------------------------------------------------------------------------
--- bugtraq:url (original)
+++ bugtraq:url Mon Sep 28 16:03:14 2015
@@ -1 +1 @@
-http://subversion.tigris.org/issues/show_bug.cgi?id=%BUGID%
+http://subversion.apache.org/issue%BUGID%
Propchange: subversion/branches/move-tracking-2/
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Mon Sep 28 16:03:14 2015
@@ -61,6 +61,7 @@
/subversion/branches/multi-layer-moves:1239019-1300930
/subversion/branches/nfc-nfd-aware-client:870276,870376
/subversion/branches/node_pool:1304828-1305388
+/subversion/branches/patch-exec:1692717-1705390
/subversion/branches/performance: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,1029339-1029340,1029342,10
29344,1030763,1030827,1031203,1031235,1032285,1032333,1033040,1033057,1033294,1035869,1035882,1039511,1043705,1053735,1056015,1066452,1067683,1067697-1078365
/subversion/branches/pin-externals:1643757-1659392
/subversion/branches/py-tests-as-modules:956579-1033052
@@ -93,4 +94,4 @@
/subversion/branches/verify-at-commit:1462039-1462408
/subversion/branches/verify-keep-going:1439280-1546110
/subversion/branches/wc-collate-path:1402685-1480384
-/subversion/trunk:1606692-1704317
+/subversion/trunk:1606692-1705711
Propchange: subversion/branches/move-tracking-2/subversion/
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Mon Sep 28 16:03:14 2015
@@ -82,4 +82,4 @@
/subversion/branches/verify-at-commit/subversion:1462039-1462408
/subversion/branches/verify-keep-going/subversion:1439280-1546110
/subversion/branches/wc-collate-path/subversion:1402685-1480384
-/subversion/trunk/subversion:1606692-1704317
+/subversion/trunk/subversion:1606692-1705711
Modified: subversion/branches/move-tracking-2/subversion/include/private/svn_diff_private.h
URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/include/private/svn_diff_private.h?rev=1705712&r1=1705711&r2=1705712&view=diff
==============================================================================
--- subversion/branches/move-tracking-2/subversion/include/private/svn_diff_private.h (original)
+++ subversion/branches/move-tracking-2/subversion/include/private/svn_diff_private.h Mon Sep 28 16:03:14 2015
@@ -113,6 +113,33 @@ svn_diff__display_prop_diffs(svn_stream_
void *cancel_baton,
apr_pool_t *scratch_pool);
+/** Create a hunk object that adds a single line without newline. Return the
+ * new object in @a *hunk.
+ *
+ * @a line is the added text, without a trailing newline.
+ *
+ * The hunk will be associated with @a patch.
+ */
+svn_error_t *
+svn_diff_hunk__create_adds_single_line(svn_diff_hunk_t **hunk,
+ const char *line,
+ svn_patch_t *patch,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool);
+
+/** Create a hunk object that deletes a single line without newline. Return
+ * the new object in @a *hunk.
+ *
+ * @a line is the deleted text, without a trailing newline.
+ *
+ * The hunk will be associated with @a patch.
+ */
+svn_error_t *
+svn_diff_hunk__create_deletes_single_line(svn_diff_hunk_t **hunk,
+ const char *line,
+ svn_patch_t *patch,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool);
#ifdef __cplusplus
}
Modified: subversion/branches/move-tracking-2/subversion/include/svn_dav.h
URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/include/svn_dav.h?rev=1705712&r1=1705711&r2=1705712&view=diff
==============================================================================
--- subversion/branches/move-tracking-2/subversion/include/svn_dav.h (original)
+++ subversion/branches/move-tracking-2/subversion/include/svn_dav.h Mon Sep 28 16:03:14 2015
@@ -386,6 +386,15 @@ extern "C" {
#define SVN_DAV_NS_DAV_SVN_REVERSE_FILE_REVS\
SVN_DAV_PROP_NS_DAV "svn/reverse-file-revs"
+/** Presence of this in a DAV header in an OPTIONS response indicates
+ * that the transmitter (in this case, the server) knows how to handle
+ * svndiff1 format encoding.
+ *
+ * @since New in 1.10.
+ */
+#define SVN_DAV_NS_DAV_SVN_SVNDIFF1\
+ SVN_DAV_PROP_NS_DAV "svn/svndiff1"
+
/** @} */
Modified: subversion/branches/move-tracking-2/subversion/include/svn_diff.h
URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/include/svn_diff.h?rev=1705712&r1=1705711&r2=1705712&view=diff
==============================================================================
--- subversion/branches/move-tracking-2/subversion/include/svn_diff.h (original)
+++ subversion/branches/move-tracking-2/subversion/include/svn_diff.h Mon Sep 28 16:03:14 2015
@@ -1215,10 +1215,36 @@ typedef struct svn_prop_patch_t {
* A binary patch representation. This basically describes replacing one
* exact binary representation with another one.
*
- * @since new in 1.10. */
+ * @since New in 1.10. */
typedef struct svn_diff_binary_patch_t svn_diff_binary_patch_t;
/**
+ * Creates a stream allocated in @a result_pool from which the original
+ * (pre-patch-application) version of the binary patched file can be read.
+ *
+ * @note Like many svn_diff_get functions over patches, this is implemented
+ * as reading from the backing patch file. Therefore it is recommended to
+ * read the whole stream before using other functions on the same patch file.
+ *
+ * @since New in 1.10 */
+svn_stream_t *
+svn_diff_get_binary_diff_original_stream(const svn_diff_binary_patch_t *bpatch,
+ apr_pool_t *result_pool);
+
+/**
+ * Creates a stream allocated in @a result_pool from which the resulting
+ * (post-patch-application) version of the binary patched file can be read.
+ *
+ * @note Like many svn_diff_get functions over patches, this is implemented
+ * as reading from the backing patch file. Therefore it is recommended to
+ * read the whole stream before using other functions on the same patch file.
+ *
+ * @since New in 1.10 */
+svn_stream_t *
+svn_diff_get_binary_diff_result_stream(const svn_diff_binary_patch_t *bpatch,
+ apr_pool_t *result_pool);
+
+/**
* Data type to manage parsing of patches.
* API users should not allocate structures of this type directly.
*
@@ -1262,6 +1288,24 @@ typedef struct svn_patch_t {
* to apply it as parsed from the file.
* @since New in 1.10. */
svn_diff_binary_patch_t *binary_patch;
+
+ /** The old and new executability bits, as retrieved from the patch file.
+ *
+ * A patch may specify an executability change via @a old_executable_p and
+ * / @a new_executable_p, via a #SVN_PROP_EXECUTABLE propchange hunk, or both
+ * ways; however, if both ways are used, they must specify the same semantic
+ * change.
+ *
+ * #svn_tristate_unknown indicates the patch does not specify the
+ * corresponding bit.
+ *
+ * @since New in 1.10.
+ */
+ /* ### This is currently not parsed out of "index" lines (where it
+ * ### serves as an assertion of the executability state, without
+ * ### changing it). */
+ svn_tristate_t old_executable_p;
+ svn_tristate_t new_executable_p;
} svn_patch_t;
/** An opaque type representing an open patch file.
Modified: subversion/branches/move-tracking-2/subversion/include/svn_error_codes.h
URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/include/svn_error_codes.h?rev=1705712&r1=1705711&r2=1705712&view=diff
==============================================================================
--- subversion/branches/move-tracking-2/subversion/include/svn_error_codes.h (original)
+++ subversion/branches/move-tracking-2/subversion/include/svn_error_codes.h Mon Sep 28 16:03:14 2015
@@ -1594,6 +1594,11 @@ SVN_ERROR_START
SVN_ERR_DIFF_CATEGORY_START + 0,
"Diff data source modified unexpectedly")
+ /** @since New in 1.10 */
+ SVN_ERRDEF(SVN_ERR_DIFF_UNEXPECTED_DATA,
+ SVN_ERR_DIFF_CATEGORY_START + 1,
+ "Diff data unexpected")
+
/* libsvn_ra_serf errors */
/** @since New in 1.5.
@deprecated SSPI now handled by serf rather than libsvn_ra_serf. */
Modified: subversion/branches/move-tracking-2/subversion/libsvn_client/client.h
URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/libsvn_client/client.h?rev=1705712&r1=1705711&r2=1705712&view=diff
==============================================================================
--- subversion/branches/move-tracking-2/subversion/libsvn_client/client.h (original)
+++ subversion/branches/move-tracking-2/subversion/libsvn_client/client.h Mon Sep 28 16:03:14 2015
@@ -1072,9 +1072,13 @@ svn_client__ensure_revprop_table(apr_has
EXPAND_KEYWORDS operates as per the EXPAND argument to
svn_subst_stream_translated, which see. If NORMALIZE_EOLS is TRUE and
LOCAL_ABSPATH requires translation, then normalize the line endings in
- *NORMAL_STREAM.
+ *NORMAL_STREAM to "\n" if the stream has svn:eol-style set.
- Uses SCRATCH_POOL for temporary allocations. */
+ Note that this IS NOT the repository normal form of the stream as that
+ would use "\r\n" if set to CRLF and "\r" if set to CR.
+
+ The stream is allocated in RESULT_POOL and temporary SCRATCH_POOL is
+ used for temporary allocations. */
svn_error_t *
svn_client__get_normalized_stream(svn_stream_t **normal_stream,
svn_wc_context_t *wc_ctx,
Modified: subversion/branches/move-tracking-2/subversion/libsvn_client/patch.c
URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/libsvn_client/patch.c?rev=1705712&r1=1705711&r2=1705712&view=diff
==============================================================================
--- subversion/branches/move-tracking-2/subversion/libsvn_client/patch.c (original)
+++ subversion/branches/move-tracking-2/subversion/libsvn_client/patch.c Mon Sep 28 16:03:14 2015
@@ -46,6 +46,7 @@
#include "private/svn_eol_private.h"
#include "private/svn_wc_private.h"
#include "private/svn_dep_compat.h"
+#include "private/svn_diff_private.h"
#include "private/svn_string_private.h"
#include "private/svn_subr_private.h"
#include "private/svn_sorts_private.h"
@@ -218,6 +219,12 @@ typedef struct patch_target_t {
/* True if at least one property hunk was rejected. */
svn_boolean_t had_prop_rejects;
+ /* True if at least one hunk was handled as already applied */
+ svn_boolean_t had_already_applied;
+
+ /* True if at least one property hunk was handled as already applied */
+ svn_boolean_t had_prop_already_applied;
+
/* True if the target file had local modifications before the
* patch was applied to it. */
svn_boolean_t local_mods;
@@ -371,17 +378,17 @@ obtain_eol_and_keywords_for_file(apr_has
* Indicate in TARGET->SKIPPED whether the target should be skipped.
* STRIP_COUNT specifies the number of leading path components
* which should be stripped from target paths in the patch.
- * PROP_CHANGES_ONLY specifies whether the target path is allowed to have
- * only property changes, and no content changes (in which case the target
- * must be a directory).
+ * HAS_TEXT_CHANGES specifies whether the target path will have some text
+ * changes applied, implying that the target should be a file and not a
+ * directory.
* Use RESULT_POOL for allocations of fields in TARGET.
* Use SCRATCH_POOL for all other allocations. */
static svn_error_t *
resolve_target_path(patch_target_t *target,
const char *path_from_patchfile,
- const char *wcroot_abspath,
+ const char *root_abspath,
int strip_count,
- svn_boolean_t prop_changes_only,
+ svn_boolean_t has_text_changes,
svn_wc_context_t *wc_ctx,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
@@ -394,8 +401,8 @@ resolve_target_path(patch_target_t *targ
target->canon_path_from_patchfile = svn_dirent_internal_style(
path_from_patchfile, result_pool);
- /* We allow properties to be set on the wc root dir. */
- if (! prop_changes_only && target->canon_path_from_patchfile[0] == '\0')
+ /* We can't handle text changes on the patch root dir. */
+ if (has_text_changes && target->canon_path_from_patchfile[0] == '\0')
{
/* An empty patch target path? What gives? Skip this. */
target->skipped = TRUE;
@@ -412,14 +419,14 @@ resolve_target_path(patch_target_t *targ
if (svn_dirent_is_absolute(stripped_path))
{
- target->local_relpath = svn_dirent_is_child(wcroot_abspath,
+ target->local_relpath = svn_dirent_is_child(root_abspath,
stripped_path,
result_pool);
if (! target->local_relpath)
{
/* The target path is either outside of the working copy
- * or it is the working copy itself. Skip it. */
+ * or it is the patch root itself. Skip it. */
target->skipped = TRUE;
target->local_abspath = NULL;
target->local_relpath = stripped_path;
@@ -432,9 +439,9 @@ resolve_target_path(patch_target_t *targ
}
/* Make sure the path is secure to use. We want the target to be inside
- * of the working copy and not be fooled by symlinks it might contain. */
+ * the locked tree and not be fooled by symlinks it might contain. */
SVN_ERR(svn_dirent_is_under_root(&under_root,
- &target->local_abspath, wcroot_abspath,
+ &target->local_abspath, root_abspath,
target->local_relpath, result_pool));
if (! under_root)
@@ -485,17 +492,23 @@ resolve_target_path(patch_target_t *targ
if (target->locally_deleted)
{
const char *moved_to_abspath;
+ const char *op_root_abspath;
- SVN_ERR(svn_wc__node_was_moved_away(&moved_to_abspath, NULL,
+ SVN_ERR(svn_wc__node_was_moved_away(&moved_to_abspath, &op_root_abspath,
wc_ctx, target->local_abspath,
result_pool, scratch_pool));
if (moved_to_abspath)
{
target->local_abspath = moved_to_abspath;
- target->local_relpath = svn_dirent_skip_ancestor(wcroot_abspath,
- moved_to_abspath);
- SVN_ERR_ASSERT(target->local_relpath &&
- target->local_relpath[0] != '\0');
+ target->local_relpath = svn_dirent_skip_ancestor(root_abspath,
+ moved_to_abspath);
+
+ if (!target->local_relpath || target->local_relpath[0] == '\0')
+ {
+ /* The target path is outside of the patch area. Skip it. */
+ target->skipped = TRUE;
+ return SVN_NO_ERROR;
+ }
/* As far as we are concerned this target is not locally deleted. */
target->locally_deleted = FALSE;
@@ -541,7 +554,7 @@ readline_prop(void *baton, svn_stringbuf
svn_boolean_t *eof, apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
- prop_read_baton_t *b = (prop_read_baton_t *)baton;
+ prop_read_baton_t *b = baton;
svn_stringbuf_t *str = NULL;
const char *c;
svn_boolean_t found_eof;
@@ -606,7 +619,8 @@ readline_prop(void *baton, svn_stringbuf
static svn_error_t *
tell_prop(void *baton, apr_off_t *offset, apr_pool_t *scratch_pool)
{
- prop_read_baton_t *b = (prop_read_baton_t *)baton;
+ prop_read_baton_t *b = baton;
+
*offset = b->offset;
return SVN_NO_ERROR;
}
@@ -616,7 +630,8 @@ tell_prop(void *baton, apr_off_t *offset
static svn_error_t *
seek_prop(void *baton, apr_off_t offset, apr_pool_t *scratch_pool)
{
- prop_read_baton_t *b = (prop_read_baton_t *)baton;
+ prop_read_baton_t *b = baton;
+
b->offset = offset;
return SVN_NO_ERROR;
}
@@ -627,7 +642,8 @@ static svn_error_t *
write_prop(void *baton, const char *buf, apr_size_t len,
apr_pool_t *scratch_pool)
{
- svn_stringbuf_t *patched_value = (svn_stringbuf_t *)baton;
+ svn_stringbuf_t *patched_value = baton;
+
svn_stringbuf_appendbytes(patched_value, buf, len);
return SVN_NO_ERROR;
}
@@ -717,71 +733,15 @@ readline_file(void *baton, svn_stringbuf
svn_boolean_t *eof, apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
- apr_file_t *file = (apr_file_t *)baton;
- svn_stringbuf_t *str = NULL;
- apr_size_t numbytes;
- char c;
- svn_boolean_t found_eof;
-
- /* Read bytes into STR up to and including, but not storing,
- * the next EOL sequence. */
- *eol_str = NULL;
- numbytes = 1;
- found_eof = FALSE;
- while (!found_eof)
- {
- SVN_ERR(svn_io_file_read_full2(file, &c, sizeof(c), &numbytes,
- &found_eof, scratch_pool));
- if (numbytes != 1)
- {
- found_eof = TRUE;
- break;
- }
-
- if (c == '\n')
- {
- *eol_str = "\n";
- }
- else if (c == '\r')
- {
- *eol_str = "\r";
-
- if (!found_eof)
- {
- apr_off_t pos;
+ apr_file_t *file = baton;
- /* Check for "\r\n" by peeking at the next byte. */
- pos = 0;
- SVN_ERR(svn_io_file_seek(file, APR_CUR, &pos, scratch_pool));
- SVN_ERR(svn_io_file_read_full2(file, &c, sizeof(c), &numbytes,
- &found_eof, scratch_pool));
- if (numbytes == 1 && c == '\n')
- {
- *eol_str = "\r\n";
- }
- else
- {
- /* Pretend we never peeked. */
- SVN_ERR(svn_io_file_seek(file, APR_SET, &pos, scratch_pool));
- found_eof = FALSE;
- numbytes = 1;
- }
- }
- }
- else
- {
- if (str == NULL)
- str = svn_stringbuf_create_ensure(80, result_pool);
- svn_stringbuf_appendbyte(str, c);
- }
-
- if (*eol_str)
- break;
- }
+ SVN_ERR(svn_io_file_readline(file, line, eol_str, eof, APR_SIZE_MAX,
+ result_pool, scratch_pool));
- if (eof)
- *eof = found_eof;
- *line = str;
+ if (!(*line)->len)
+ *line = NULL;
+ else
+ *eof = FALSE;
return SVN_NO_ERROR;
}
@@ -792,7 +752,8 @@ readline_file(void *baton, svn_stringbuf
static svn_error_t *
tell_file(void *baton, apr_off_t *offset, apr_pool_t *scratch_pool)
{
- apr_file_t *file = (apr_file_t *)baton;
+ apr_file_t *file = baton;
+
*offset = 0;
SVN_ERR(svn_io_file_seek(file, APR_CUR, offset, scratch_pool));
return SVN_NO_ERROR;
@@ -803,7 +764,8 @@ tell_file(void *baton, apr_off_t *offset
static svn_error_t *
seek_file(void *baton, apr_off_t offset, apr_pool_t *scratch_pool)
{
- apr_file_t *file = (apr_file_t *)baton;
+ apr_file_t *file = baton;
+
SVN_ERR(svn_io_file_seek(file, APR_SET, &offset, scratch_pool));
return SVN_NO_ERROR;
}
@@ -814,7 +776,8 @@ static svn_error_t *
write_file(void *baton, const char *buf, apr_size_t len,
apr_pool_t *scratch_pool)
{
- apr_file_t *file = (apr_file_t *)baton;
+ apr_file_t *file = baton;
+
SVN_ERR(svn_io_file_write_full(file, buf, len, &len, scratch_pool));
return SVN_NO_ERROR;
}
@@ -958,6 +921,41 @@ choose_target_filename(const svn_patch_t
return (old < new) ? patch->old_filename : patch->new_filename;
}
+/* Return whether the svn:executable proppatch and the out-of-band
+ * executability metadata contradict each other, assuming both are present.
+ */
+static svn_boolean_t
+contradictory_executability(const svn_patch_t *patch,
+ const prop_patch_target_t *target)
+{
+ switch (target->operation)
+ {
+ case svn_diff_op_added:
+ return patch->new_executable_p == svn_tristate_false;
+
+ case svn_diff_op_deleted:
+ return patch->new_executable_p == svn_tristate_true;
+
+ case svn_diff_op_unchanged:
+ /* ### Can this happen? */
+ return (patch->old_executable_p != svn_tristate_unknown
+ && patch->new_executable_p != svn_tristate_unknown
+ && patch->old_executable_p != patch->new_executable_p);
+
+ case svn_diff_op_modified:
+ /* Can't happen: the property should only ever be added or deleted,
+ * but never modified from one valid value to another. */
+ return (patch->old_executable_p != svn_tristate_unknown
+ && patch->new_executable_p != svn_tristate_unknown
+ && patch->old_executable_p == patch->new_executable_p);
+
+ default:
+ /* Can't happen: the proppatch parser never generates other values. */
+ SVN_ERR_MALFUNCTION_NO_RETURN();
+ }
+}
+
+
/* Attempt to initialize a *PATCH_TARGET structure for a target file
* described by PATCH. Use working copy context WC_CTX.
* STRIP_COUNT specifies the number of leading path components
@@ -972,32 +970,17 @@ choose_target_filename(const svn_patch_t
static svn_error_t *
init_patch_target(patch_target_t **patch_target,
const svn_patch_t *patch,
- const char *wcroot_abspath,
+ const char *root_abspath,
svn_wc_context_t *wc_ctx, int strip_count,
svn_boolean_t remove_tempfiles,
apr_pool_t *result_pool, apr_pool_t *scratch_pool)
{
patch_target_t *target;
target_content_t *content;
- svn_boolean_t has_prop_changes = FALSE;
- svn_boolean_t prop_changes_only = FALSE;
+ svn_boolean_t has_text_changes = FALSE;
- {
- apr_hash_index_t *hi;
-
- for (hi = apr_hash_first(scratch_pool, patch->prop_patches);
- hi;
- hi = apr_hash_next(hi))
- {
- svn_prop_patch_t *prop_patch = apr_hash_this_val(hi);
- if (! has_prop_changes)
- has_prop_changes = prop_patch->hunks->nelts > 0;
- else
- break;
- }
- }
-
- prop_changes_only = has_prop_changes && patch->hunks->nelts == 0;
+ has_text_changes = ((patch->hunks && patch->hunks->nelts > 0)
+ || patch->binary_patch);
content = apr_pcalloc(result_pool, sizeof(*content));
@@ -1015,9 +998,12 @@ init_patch_target(patch_target_t **patch
target->kind_on_disk = svn_node_none;
target->content = content;
target->prop_targets = apr_hash_make(result_pool);
+ if (patch->new_executable_p != svn_tristate_unknown)
+ /* May also be set by apply_hunk(). */
+ target->has_prop_changes = TRUE;
SVN_ERR(resolve_target_path(target, choose_target_filename(patch),
- wcroot_abspath, strip_count, prop_changes_only,
+ root_abspath, strip_count, has_text_changes,
wc_ctx, result_pool, scratch_pool));
*patch_target = target;
if (! target->skipped)
@@ -1095,7 +1081,7 @@ init_patch_target(patch_target_t **patch
if (svn_dirent_is_absolute(move_target_path))
{
- move_target_relpath = svn_dirent_is_child(wcroot_abspath,
+ move_target_relpath = svn_dirent_is_child(root_abspath,
move_target_path,
scratch_pool);
if (! move_target_relpath)
@@ -1113,7 +1099,7 @@ init_patch_target(patch_target_t **patch
/* Make sure the move target path is secure to use. */
SVN_ERR(svn_dirent_is_under_root(&under_root,
&target->move_target_abspath,
- wcroot_abspath,
+ root_abspath,
move_target_relpath, result_pool));
if (! under_root)
{
@@ -1188,6 +1174,7 @@ init_patch_target(patch_target_t **patch
if (! target->skipped)
{
apr_hash_index_t *hi;
+ prop_patch_target_t *prop_executable_target;
for (hi = apr_hash_first(result_pool, patch->prop_patches);
hi;
@@ -1204,6 +1191,99 @@ init_patch_target(patch_target_t **patch
result_pool, scratch_pool));
svn_hash_sets(target->prop_targets, prop_name, prop_target);
}
+
+ /* Now, check for an out-of-band mode change and convert it to
+ * an svn:executable property patch. */
+ prop_executable_target = svn_hash_gets(target->prop_targets,
+ SVN_PROP_EXECUTABLE);
+ if (patch->new_executable_p != svn_tristate_unknown
+ && prop_executable_target)
+ {
+ if (contradictory_executability(patch, prop_executable_target))
+ /* Invalid input: specifies both git-like "new mode" lines and
+ * svn-like addition/removal of svn:executable.
+ *
+ * If this were merely a hunk that didn't apply, we'd reject it
+ * and move on. However, this is a self-contradictory hunk;
+ * it has no unambiguous interpretation. Therefore: */
+ return svn_error_createf(SVN_ERR_INVALID_INPUT, NULL,
+ _("Invalid patch: specifies "
+ "contradicting mode changes and "
+ "%s changes (for '%s')"),
+ SVN_PROP_EXECUTABLE,
+ target->local_abspath);
+ else
+ /* We have two representations of the same change.
+ *
+ * In the caller, there will be two hunk_info_t's for the
+ * patch: one generated from the property diff and one
+ * generated from the out-of-band mode change. Both hunks will
+ * be processed, but the output will be as though there was
+ * just one hunk.
+ *
+ * The reason there will be only a single notification is not
+ * specific to SVN_PROP_EXECUTABLE but generic to all property
+ * patches: if a patch file contains two identical property
+ * hunks (e.g.,
+ * svn ps k v iota; svn diff iota >patch; svn diff iota >>patch
+ * ), applying the patch file will only produce a single ' U'
+ * notification.
+ *
+ * In contrast, the same for file-content hunks will result in
+ * a 'U' notification followed by a 'G' notification. (The 'U'
+ * for the first copy of the hunk; the 'G' for the second.)
+ */
+ ;
+ }
+ else if (patch->new_executable_p != svn_tristate_unknown
+ && !prop_executable_target)
+ {
+ svn_diff_operation_kind_t operation;
+ svn_boolean_t nothing_to_do = FALSE;
+ prop_patch_target_t *prop_target;
+
+ if (patch->old_executable_p == patch->new_executable_p)
+ {
+ /* Noop change. */
+ operation = svn_diff_op_unchanged;
+ }
+ else switch (patch->old_executable_p)
+ {
+ case svn_tristate_false:
+ /* Made executable. */
+ operation = svn_diff_op_added;
+ break;
+
+ case svn_tristate_true:
+ /* Made non-executable. */
+ operation = svn_diff_op_deleted;
+ break;
+
+ case svn_tristate_unknown:
+ if (patch->new_executable_p == svn_tristate_true)
+ /* New, executable file. */
+ operation = svn_diff_op_added;
+ else
+ /* New, non-executable file. That's not a change. */
+ nothing_to_do = TRUE;
+ break;
+
+ default:
+ /* NOTREACHED */
+ SVN_ERR_MALFUNCTION();
+ }
+
+ if (! nothing_to_do)
+ {
+ SVN_ERR(init_prop_target(&prop_target,
+ SVN_PROP_EXECUTABLE,
+ operation,
+ wc_ctx, target->local_abspath,
+ result_pool, scratch_pool));
+ svn_hash_sets(target->prop_targets, SVN_PROP_EXECUTABLE,
+ prop_target);
+ }
+ }
}
}
@@ -1553,14 +1633,14 @@ match_existing_target(svn_boolean_t *mat
*match = FALSE;
return SVN_NO_ERROR;
}
- }
- while (lines_matched && ! content->eof && ! hunk_eof);
- svn_pool_destroy(iterpool);
+ }
+ while (lines_matched && ! content->eof && ! hunk_eof);
+ svn_pool_destroy(iterpool);
- *match = (lines_matched && content->eof == hunk_eof);
- SVN_ERR(seek_to_line(content, saved_line, scratch_pool));
+ *match = (lines_matched && content->eof == hunk_eof);
+ SVN_ERR(seek_to_line(content, saved_line, scratch_pool));
- return SVN_NO_ERROR;
+ return SVN_NO_ERROR;
}
/* Determine the line at which a HUNK applies to CONTENT of the TARGET
@@ -1805,9 +1885,15 @@ get_hunk_info(hunk_info_t **hi, patch_ta
SVN_ERR(seek_to_line(content, saved_line, scratch_pool));
}
+ else if (!content->existed && svn_diff_hunk_get_modified_start(hunk) == 0)
+ {
+ /* The hunk wants to delete a file or property which doesn't exist. */
+ matched_line = 0;
+ already_applied = TRUE;
+ }
else
{
- /* The hunk wants to modify a file which doesn't exist. */
+ /* The hunk wants to modify a file or property which doesn't exist. */
matched_line = 0;
}
@@ -2122,11 +2208,19 @@ send_patch_notification(const patch_targ
notify->content_state = svn_wc_notify_state_merged;
else if (target->has_text_changes)
notify->content_state = svn_wc_notify_state_changed;
+ else if (target->had_already_applied)
+ notify->content_state = svn_wc_notify_state_merged;
+ else
+ notify->content_state = svn_wc_notify_state_unchanged;
if (target->had_prop_rejects)
notify->prop_state = svn_wc_notify_state_conflicted;
else if (target->has_prop_changes)
notify->prop_state = svn_wc_notify_state_changed;
+ else if (target->had_prop_already_applied)
+ notify->prop_state = svn_wc_notify_state_merged;
+ else
+ notify->prop_state = svn_wc_notify_state_unchanged;
}
ctx->notify_func2(ctx->notify_baton2, notify, pool);
@@ -2168,8 +2262,9 @@ send_patch_notification(const patch_targ
hunk_info_t *);
/* Don't notify on the hunk level for added or deleted props. */
- if (prop_target->operation != svn_diff_op_added &&
+ if ((prop_target->operation != svn_diff_op_added &&
prop_target->operation != svn_diff_op_deleted)
+ || hi->rejected || hi->already_applied)
SVN_ERR(send_hunk_notification(hi, target, prop_target->name,
ctx, iterpool));
}
@@ -2260,6 +2355,7 @@ apply_one_patch(patch_target_t **patch_t
static const svn_linenum_t MAX_FUZZ = 2;
apr_hash_index_t *hash_index;
svn_linenum_t previous_offset = 0;
+ svn_boolean_t has_text_changes = FALSE;
SVN_ERR(init_patch_target(&target, patch, abs_wc_path, wc_ctx, strip_count,
remove_tempfiles, result_pool, scratch_pool));
@@ -2283,77 +2379,157 @@ apply_one_patch(patch_target_t **patch_t
}
iterpool = svn_pool_create(scratch_pool);
- /* Match hunks. */
- for (i = 0; i < patch->hunks->nelts; i++)
+
+ if (patch->hunks && patch->hunks->nelts)
{
- svn_diff_hunk_t *hunk;
- hunk_info_t *hi;
- svn_linenum_t fuzz = 0;
+ /* Match hunks. */
+ for (i = 0; i < patch->hunks->nelts; i++)
+ {
+ svn_diff_hunk_t *hunk;
+ hunk_info_t *hi;
+ svn_linenum_t fuzz = 0;
- svn_pool_clear(iterpool);
+ svn_pool_clear(iterpool);
- if (cancel_func)
- SVN_ERR(cancel_func(cancel_baton));
+ if (cancel_func)
+ SVN_ERR(cancel_func(cancel_baton));
- hunk = APR_ARRAY_IDX(patch->hunks, i, svn_diff_hunk_t *);
+ hunk = APR_ARRAY_IDX(patch->hunks, i, svn_diff_hunk_t *);
- /* Determine the line the hunk should be applied at.
- * If no match is found initially, try with fuzz. */
- do
- {
- SVN_ERR(get_hunk_info(&hi, target, target->content, hunk, fuzz,
- previous_offset,
- ignore_whitespace,
- FALSE /* is_prop_hunk */,
- cancel_func, cancel_baton,
- result_pool, iterpool));
- fuzz++;
+ /* Determine the line the hunk should be applied at.
+ * If no match is found initially, try with fuzz. */
+ do
+ {
+ SVN_ERR(get_hunk_info(&hi, target, target->content, hunk, fuzz,
+ previous_offset,
+ ignore_whitespace,
+ FALSE /* is_prop_hunk */,
+ cancel_func, cancel_baton,
+ result_pool, iterpool));
+ fuzz++;
+ }
+ while (hi->rejected && fuzz <= MAX_FUZZ && ! hi->already_applied);
+
+ if (hi->matched_line)
+ previous_offset
+ = hi->matched_line - svn_diff_hunk_get_original_start(hunk);
+
+ APR_ARRAY_PUSH(target->content->hunks, hunk_info_t *) = hi;
}
- while (hi->rejected && fuzz <= MAX_FUZZ && ! hi->already_applied);
- if (hi->matched_line)
- previous_offset
- = hi->matched_line - svn_diff_hunk_get_original_start(hunk);
+ /* Hunks are applied in the order determined by the matched line and
+ this may be different from the order of the original lines. */
+ svn_sort__array(target->content->hunks, sort_matched_hunks);
- APR_ARRAY_PUSH(target->content->hunks, hunk_info_t *) = hi;
- }
+ /* Apply or reject hunks. */
+ for (i = 0; i < target->content->hunks->nelts; i++)
+ {
+ hunk_info_t *hi;
+
+ svn_pool_clear(iterpool);
+
+ if (cancel_func)
+ SVN_ERR(cancel_func(cancel_baton));
- /* Hunks are applied in the order determined by the matched line and
- this may be different from the order of the original lines. */
- svn_sort__array(target->content->hunks, sort_matched_hunks);
+ hi = APR_ARRAY_IDX(target->content->hunks, i, hunk_info_t *);
+ if (hi->already_applied)
+ {
+ target->had_already_applied = TRUE;;
+ continue;
+ }
+ else if (hi->rejected)
+ SVN_ERR(reject_hunk(target, target->content, hi->hunk,
+ NULL /* prop_name */,
+ iterpool));
+ else
+ SVN_ERR(apply_hunk(target, target->content, hi,
+ NULL /* prop_name */, iterpool));
+ }
- /* Apply or reject hunks. */
- for (i = 0; i < target->content->hunks->nelts; i++)
+ if (target->kind_on_disk == svn_node_file)
+ {
+ /* Copy any remaining lines to target. */
+ SVN_ERR(copy_lines_to_target(target->content, 0, scratch_pool));
+ if (! target->content->eof)
+ {
+ /* We could not copy the entire target file to the temporary
+ * file, and would truncate the target if we copied the
+ * temporary file on top of it. Skip this target. */
+ target->skipped = TRUE;
+ }
+ }
+ has_text_changes = TRUE;
+ }
+ else if (patch->binary_patch)
{
- hunk_info_t *hi;
+ svn_stream_t *orig_stream;
+ svn_boolean_t same;
+
+ if (target->file)
+ orig_stream = svn_stream_from_aprfile2(target->file, TRUE, iterpool);
+ else
+ orig_stream = svn_stream_empty(iterpool);
+ SVN_ERR(svn_stream_contents_same2(
+ &same, orig_stream,
+ svn_diff_get_binary_diff_original_stream(patch->binary_patch,
+ iterpool),
+ iterpool));
svn_pool_clear(iterpool);
- if (cancel_func)
- SVN_ERR(cancel_func(cancel_baton));
+ if (same)
+ {
+ /* The file in the working copy is identical to the one expected by
+ the patch... So we can write the result stream; no fuzz,
+ just a 100% match */
+
+ SVN_ERR(svn_stream_copy3(
+ svn_diff_get_binary_diff_result_stream(patch->binary_patch,
+ iterpool),
+ svn_stream_from_aprfile2(target->patched_file, TRUE,
+ iterpool),
+ cancel_func, cancel_baton,
+ iterpool));
- hi = APR_ARRAY_IDX(target->content->hunks, i, hunk_info_t *);
- if (hi->already_applied)
- continue;
- else if (hi->rejected)
- SVN_ERR(reject_hunk(target, target->content, hi->hunk,
- NULL /* prop_name */,
- iterpool));
+ has_text_changes = TRUE;
+ target->has_text_changes = TRUE;
+ }
else
- SVN_ERR(apply_hunk(target, target->content, hi,
- NULL /* prop_name */, iterpool));
- }
+ {
+ /* ### TODO: Implement a proper reject of a binary patch
- if (target->kind_on_disk == svn_node_file)
+ This should at least setup things for a proper notification,
+ and perhaps install a normal text conflict. Unlike normal unified
+ diff based patches we have all the versions we would need for
+ that in a much easier format than can be obtained from the patch
+ file. */
+ target->skipped = TRUE;
+ }
+ }
+ else if (target->move_target_abspath)
{
- /* Copy any remaining lines to target. */
- SVN_ERR(copy_lines_to_target(target->content, 0, scratch_pool));
- if (! target->content->eof)
+ /* ### Why do we do this?
+ BH: I don't know, but if we don't do this some tests
+ on git style patches break.
+
+ ### It would be much better to really move the actual file instead
+ of copying to a temporary file; move that to target and then
+ delete the original file
+
+ ### BH: I have absolutely no idea if moving directories would work.
+ */
+ if (target->kind_on_disk == svn_node_file)
{
- /* We could not copy the entire target file to the temporary file,
- * and would truncate the target if we copied the temporary file
- * on top of it. Skip this target. */
- target->skipped = TRUE;
+ /* Copy any remaining lines to target. (read: all lines) */
+ SVN_ERR(copy_lines_to_target(target->content, 0, scratch_pool));
+ if (!target->content->eof)
+ {
+ /* We could not copy the entire target file to the temporary
+ * file, and would truncate the target if we copied the
+ * temporary file on top of it. Skip this target. */
+ target->skipped = TRUE;
+ }
+ has_text_changes = TRUE;
}
}
@@ -2406,6 +2582,50 @@ apply_one_patch(patch_target_t **patch_t
}
}
+ /* Match implied property hunks. */
+ if (patch->new_executable_p != svn_tristate_unknown
+ && svn_hash_gets(target->prop_targets, SVN_PROP_EXECUTABLE))
+ {
+ hunk_info_t *hi;
+ svn_diff_hunk_t *hunk;
+ prop_patch_target_t *prop_target = svn_hash_gets(target->prop_targets,
+ SVN_PROP_EXECUTABLE);
+ const char *const value = SVN_PROP_EXECUTABLE_VALUE;
+
+ switch (prop_target->operation)
+ {
+ case svn_diff_op_added:
+ SVN_ERR(svn_diff_hunk__create_adds_single_line(&hunk, value, patch,
+ result_pool,
+ iterpool));
+ break;
+
+ case svn_diff_op_deleted:
+ SVN_ERR(svn_diff_hunk__create_deletes_single_line(&hunk, value,
+ patch,
+ result_pool,
+ iterpool));
+ break;
+
+ case svn_diff_op_unchanged:
+ /* ### What to do? */
+ break;
+
+ default:
+ SVN_ERR_MALFUNCTION();
+ }
+
+ /* Derive a hunk_info from hunk. */
+ SVN_ERR(get_hunk_info(&hi, target, prop_target->content,
+ hunk, 0 /* fuzz */, 0 /* previous_offset */,
+ ignore_whitespace,
+ TRUE /* is_prop_hunk */,
+ cancel_func, cancel_baton,
+ result_pool, iterpool));
+ if (! hi->already_applied)
+ APR_ARRAY_PUSH(prop_target->content->hunks, hunk_info_t *) = hi;
+ }
+
/* Apply or reject property hunks. */
for (hash_index = apr_hash_first(scratch_pool, target->prop_targets);
hash_index;
@@ -2424,7 +2644,10 @@ apply_one_patch(patch_target_t **patch_t
hi = APR_ARRAY_IDX(prop_target->content->hunks, i,
hunk_info_t *);
if (hi->already_applied)
- continue;
+ {
+ target->had_prop_already_applied = TRUE;
+ continue;
+ }
else if (hi->rejected)
SVN_ERR(reject_hunk(target, prop_target->content, hi->hunk,
prop_target->name,
@@ -2482,13 +2705,14 @@ apply_one_patch(patch_target_t **patch_t
if (patched_file.size == 0 && working_file.size > 0)
{
- /* If a unidiff removes all lines from a file, that usually
- * means deletion, so we can confidently schedule the target
- * for deletion. In the rare case where the unidiff was really
- * meant to replace a file with an empty one, this may not
- * be desirable. But the deletion can easily be reverted and
+ /* If a unidiff or a binary patch removes all lines from a file,
+ * that usually means deletion, so we can confidently schedule
+ * the target for deletion. In the rare case where the unidiff
+ * was really meant to replace a file with an empty one, this may
+ * not be desirable. But the deletion can easily be reverted and
* creating an empty file manually is not exactly hard either. */
- target->deleted = (target->db_kind == svn_node_file);
+ if (has_text_changes)
+ target->deleted = (target->db_kind == svn_node_file);
}
else if (patched_file.size == 0 && working_file.size == 0)
{
@@ -2520,6 +2744,9 @@ apply_one_patch(patch_target_t **patch_t
/* Try to create missing parent directories for TARGET in the working copy
* rooted at ABS_WC_PATH, and add the parents to version control.
* If the parents cannot be created, mark the target as skipped.
+ *
+ * In dry run mode record missing parents in ALREADY_ADDED
+ *
* Use client context CTX. If DRY_RUN is true, do not create missing
* parents but issue notifications only.
* Use SCRATCH_POOL for temporary allocations. */
@@ -2528,6 +2755,7 @@ create_missing_parents(patch_target_t *t
const char *abs_wc_path,
svn_client_ctx_t *ctx,
svn_boolean_t dry_run,
+ apr_hash_t *already_added,
apr_pool_t *scratch_pool)
{
const char *local_abspath;
@@ -2616,17 +2844,25 @@ create_missing_parents(patch_target_t *t
scratch_pool);
if (dry_run)
{
- if (ctx->notify_func2)
+ if (!svn_hash_gets(already_added, local_abspath))
{
- /* Just do notification. */
- svn_wc_notify_t *notify;
- notify = svn_wc_create_notify(local_abspath,
- svn_wc_notify_add,
- iterpool);
- notify->kind = svn_node_dir;
- ctx->notify_func2(ctx->notify_baton2, notify,
- iterpool);
- }
+ svn_hash_sets(already_added,
+ apr_pstrdup(apr_hash_pool_get(already_added),
+ local_abspath),
+ "");
+
+ if (ctx->notify_func2)
+ {
+ /* Just do notification. */
+ svn_wc_notify_t *notify;
+ notify = svn_wc_create_notify(local_abspath,
+ svn_wc_notify_add,
+ iterpool);
+ notify->kind = svn_node_dir;
+ ctx->notify_func2(ctx->notify_baton2, notify,
+ iterpool);
+ }
+ }
}
else
{
@@ -2653,12 +2889,17 @@ create_missing_parents(patch_target_t *t
/* Install a patched TARGET into the working copy at ABS_WC_PATH.
* Use client context CTX to retrieve WC_CTX, and possibly doing
- * notifications. If DRY_RUN is TRUE, don't modify the working copy.
+ * notifications.
+ *
+ * Pass on ALREADY_ADDED to allow recording already added ancestors
+ * in dry-run mode.
+ *
+ * If DRY_RUN is TRUE, don't modify the working copy.
* Do temporary allocations in POOL. */
static svn_error_t *
install_patched_target(patch_target_t *target, const char *abs_wc_path,
svn_client_ctx_t *ctx, svn_boolean_t dry_run,
- apr_pool_t *pool)
+ apr_hash_t *already_added, apr_pool_t *pool)
{
if (target->deleted)
{
@@ -2707,7 +2948,7 @@ install_patched_target(patch_target_t *t
}
else
SVN_ERR(create_missing_parents(target, abs_wc_path, ctx,
- dry_run, pool));
+ dry_run, already_added, pool));
}
else
@@ -3105,7 +3346,7 @@ static svn_error_t *
apply_patches(/* The path to the patch file. */
const char *patch_abspath,
/* The abspath to the working copy the patch should be applied to. */
- const char *abs_wc_path,
+ const char *root_abspath,
/* Indicates whether we're doing a dry run. */
svn_boolean_t dry_run,
/* Number of leading components to strip from patch target paths. */
@@ -3127,6 +3368,7 @@ apply_patches(/* The path to the patch f
apr_pool_t *iterpool;
svn_patch_file_t *patch_file;
apr_array_header_t *targets_info;
+ apr_hash_t *already_added = apr_hash_make(scratch_pool);
/* Try to open the patch file. */
SVN_ERR(svn_diff_open_patch_file(&patch_file, patch_abspath, scratch_pool));
@@ -3149,7 +3391,7 @@ apply_patches(/* The path to the patch f
{
patch_target_t *target;
- SVN_ERR(apply_one_patch(&target, patch, abs_wc_path,
+ SVN_ERR(apply_one_patch(&target, patch, root_abspath,
ctx->wc_ctx, strip_count,
ignore_whitespace, remove_tempfiles,
patch_func, patch_baton,
@@ -3173,21 +3415,28 @@ apply_patches(/* The path to the patch f
|| target->added
|| target->move_target_abspath
|| target->deleted)
- SVN_ERR(install_patched_target(target, abs_wc_path,
- ctx, dry_run, iterpool));
+ SVN_ERR(install_patched_target(target, root_abspath,
+ ctx, dry_run,
+ already_added, iterpool));
if (target->has_prop_changes && (!target->deleted))
SVN_ERR(install_patched_prop_targets(target, ctx,
dry_run, iterpool));
SVN_ERR(write_out_rejected_hunks(target, dry_run, iterpool));
+
+ if (target->added)
+ svn_hash_sets(already_added,
+ apr_pstrdup(scratch_pool,
+ target->local_abspath),
+ "");
}
SVN_ERR(send_patch_notification(target, ctx, iterpool));
if (target->deleted && !target->skipped)
{
SVN_ERR(check_ancestor_delete(target_info->local_abspath,
- targets_info, abs_wc_path,
+ targets_info, root_abspath,
dry_run, ctx,
scratch_pool, iterpool));
}
Modified: subversion/branches/move-tracking-2/subversion/libsvn_diff/binary_diff.c
URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/libsvn_diff/binary_diff.c?rev=1705712&r1=1705711&r2=1705712&view=diff
==============================================================================
--- subversion/branches/move-tracking-2/subversion/libsvn_diff/binary_diff.c (original)
+++ subversion/branches/move-tracking-2/subversion/libsvn_diff/binary_diff.c Mon Sep 28 16:03:14 2015
@@ -28,6 +28,10 @@
#include "svn_diff.h"
#include "svn_types.h"
+#include "diff.h"
+
+#include "svn_private_config.h"
+
/* Copies the data from ORIGINAL_STREAM to a temporary file, returning both
the original and compressed size. */
static svn_error_t *
@@ -90,6 +94,64 @@ static const char b85str[] =
"abcdefghijklmnopqrstuvwxyz"
"!#$%&()*+-;<=>?@^_`{|}~";
+/* Helper function for svn_diff__base85_decode_line */
+static svn_error_t *
+base85_value(int *value, char c)
+{
+ const char *p = strchr(b85str, c);
+ if (!p)
+ return svn_error_create(SVN_ERR_DIFF_UNEXPECTED_DATA, NULL,
+ _("Invalid base85 value"));
+
+ *value = (p - b85str);
+ return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_diff__base85_decode_line(char *output_data,
+ apr_ssize_t output_len,
+ const char *base85_data,
+ apr_ssize_t base85_len,
+ apr_pool_t *scratch_pool)
+{
+ {
+ apr_ssize_t expected_data = (output_len + 3) / 4 * 5;
+
+ if (base85_len != expected_data)
+ return svn_error_create(SVN_ERR_DIFF_UNEXPECTED_DATA, NULL,
+ _("Unexpected base85 line length"));
+ }
+
+ while (base85_len)
+ {
+ unsigned info = 0;
+ apr_ssize_t i, n;
+
+ for (i = 0; i < 5; i++)
+ {
+ int value;
+
+ SVN_ERR(base85_value(&value, base85_data[i]));
+ info *= 85;
+ info += value;
+ }
+
+ for (i = 0, n=24; i < 4; i++, n-=8)
+ {
+ if (i < output_len)
+ output_data[i] = (info >> n) & 0xFF;
+ }
+
+ base85_data += 5;
+ base85_len -= 5;
+ output_data += 4;
+ output_len -= 4;
+ }
+
+ return SVN_NO_ERROR;
+}
+
+
/* Git length encoding table for write_literal */
static const char b85lenstr[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
@@ -193,8 +255,8 @@ svn_diff_output_binary(svn_stream_t *out
SVN_ERR(svn_stream_puts(output_stream, "GIT binary patch" APR_EOL_STR));
/* ### git would first calculate if a git-delta latest->original would be
- shorter than the zipped data. For now lets assume that it is not
- and just dump the literal data */
+ shorter than the zipped data. For now lets assume that it is not
+ and just dump the literal data */
SVN_ERR(write_literal(latest_full,
svn_stream_from_aprfile2(latest_apr, FALSE, subpool),
output_stream,
@@ -204,8 +266,8 @@ svn_diff_output_binary(svn_stream_t *out
SVN_ERR(svn_stream_puts(output_stream, APR_EOL_STR));
/* ### git would first calculate if a git-delta original->latest would be
- shorter than the zipped data. For now lets assume that it is not
- and just dump the literal data */
+ shorter than the zipped data. For now lets assume that it is not
+ and just dump the literal data */
SVN_ERR(write_literal(original_full,
svn_stream_from_aprfile2(original_apr, FALSE, subpool),
output_stream,
Modified: subversion/branches/move-tracking-2/subversion/libsvn_diff/diff.h
URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/libsvn_diff/diff.h?rev=1705712&r1=1705711&r2=1705712&view=diff
==============================================================================
--- subversion/branches/move-tracking-2/subversion/libsvn_diff/diff.h (original)
+++ subversion/branches/move-tracking-2/subversion/libsvn_diff/diff.h Mon Sep 28 16:03:14 2015
@@ -214,4 +214,14 @@ svn_diff__unified_write_hunk_header(svn_
apr_pool_t *scratch_pool);
+/* Decodes a single line of base85 data in BASE85_DATA of length BASE85_LEN,
+ to OUTPUT_DATA of length OUTPUT_LEN.
+ */
+svn_error_t *
+svn_diff__base85_decode_line(char *output_data,
+ apr_ssize_t output_len,
+ const char *base85_data,
+ apr_ssize_t base85_len,
+ apr_pool_t *scratch_pool);
+
#endif /* DIFF_H */