You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by hw...@apache.org on 2010/11/04 21:48:30 UTC
svn commit: r1031230 [4/21] - in /subversion/branches/py-tests-as-modules:
./ build/ build/ac-macros/ build/win32/ contrib/client-side/ notes/
notes/http-and-webdav/ notes/wc-ng/ subversion/bindings/ctypes-python/csvn/
subversion/bindings/javahl/native...
Modified: subversion/branches/py-tests-as-modules/subversion/libsvn_client/deprecated.c
URL: http://svn.apache.org/viewvc/subversion/branches/py-tests-as-modules/subversion/libsvn_client/deprecated.c?rev=1031230&r1=1031229&r2=1031230&view=diff
==============================================================================
--- subversion/branches/py-tests-as-modules/subversion/libsvn_client/deprecated.c (original)
+++ subversion/branches/py-tests-as-modules/subversion/libsvn_client/deprecated.c Thu Nov 4 20:48:21 2010
@@ -620,7 +620,7 @@ svn_client_move5(svn_commit_info_t **com
cb.info = commit_info_p;
cb.pool = pool;
- return svn_client_move6(src_paths, dst_path, force, move_as_child,
+ return svn_client_move6(src_paths, dst_path, move_as_child,
make_parents, revprop_table,
capture_commit_info, &cb, ctx, pool);
}
@@ -637,6 +637,7 @@ svn_client_move4(svn_commit_info_t **com
apr_array_make(pool, 1, sizeof(const char *));
APR_ARRAY_PUSH(src_paths, const char *) = src_path;
+
return svn_client_move5(commit_info_p, src_paths, dst_path, force, FALSE,
FALSE, NULL, ctx, pool);
}
@@ -1010,8 +1011,8 @@ svn_client_diff_summarize_peg(const char
/*** From export.c ***/
svn_error_t *
svn_client_export4(svn_revnum_t *result_rev,
- const char *from,
- const char *to,
+ const char *from_path_or_url,
+ const char *to_path,
const svn_opt_revision_t *peg_revision,
const svn_opt_revision_t *revision,
svn_boolean_t overwrite,
@@ -1021,15 +1022,15 @@ svn_client_export4(svn_revnum_t *result_
svn_client_ctx_t *ctx,
apr_pool_t *pool)
{
- return svn_client_export5(result_rev, from, to, peg_revision, revision,
- overwrite, ignore_externals, FALSE, depth,
- native_eol, ctx, pool);
+ return svn_client_export5(result_rev, from_path_or_url, to_path,
+ peg_revision, revision, overwrite, ignore_externals,
+ FALSE, depth, native_eol, ctx, pool);
}
svn_error_t *
svn_client_export3(svn_revnum_t *result_rev,
- const char *from,
- const char *to,
+ const char *from_path_or_url,
+ const char *to_path,
const svn_opt_revision_t *peg_revision,
const svn_opt_revision_t *revision,
svn_boolean_t overwrite,
@@ -1039,16 +1040,16 @@ svn_client_export3(svn_revnum_t *result_
svn_client_ctx_t *ctx,
apr_pool_t *pool)
{
- return svn_client_export4(result_rev, from, to, peg_revision, revision,
- overwrite, ignore_externals,
+ return svn_client_export4(result_rev, from_path_or_url, to_path,
+ peg_revision, revision, overwrite, ignore_externals,
SVN_DEPTH_INFINITY_OR_FILES(recurse),
native_eol, ctx, pool);
}
svn_error_t *
svn_client_export2(svn_revnum_t *result_rev,
- const char *from,
- const char *to,
+ const char *from_path_or_url,
+ const char *to_path,
svn_opt_revision_t *revision,
svn_boolean_t force,
const char *native_eol,
@@ -1059,23 +1060,23 @@ svn_client_export2(svn_revnum_t *result_
peg_revision.kind = svn_opt_revision_unspecified;
- return svn_client_export3(result_rev, from, to, &peg_revision,
- revision, force, FALSE, TRUE,
+ return svn_client_export3(result_rev, from_path_or_url, to_path,
+ &peg_revision, revision, force, FALSE, TRUE,
native_eol, ctx, pool);
}
svn_error_t *
svn_client_export(svn_revnum_t *result_rev,
- const char *from,
- const char *to,
+ const char *from_path_or_url,
+ const char *to_path,
svn_opt_revision_t *revision,
svn_boolean_t force,
svn_client_ctx_t *ctx,
apr_pool_t *pool)
{
- return svn_client_export2(result_rev, from, to, revision, force, NULL, ctx,
- pool);
+ return svn_client_export2(result_rev, from_path_or_url, to_path, revision,
+ force, NULL, ctx, pool);
}
/*** From list.c ***/
@@ -1337,6 +1338,27 @@ svn_client_log(const apr_array_header_t
/*** From merge.c ***/
svn_error_t *
+svn_client_merge3(const char *source1,
+ const svn_opt_revision_t *revision1,
+ const char *source2,
+ const svn_opt_revision_t *revision2,
+ const char *target_wcpath,
+ svn_depth_t depth,
+ svn_boolean_t ignore_ancestry,
+ svn_boolean_t force,
+ svn_boolean_t record_only,
+ svn_boolean_t dry_run,
+ const apr_array_header_t *merge_options,
+ svn_client_ctx_t *ctx,
+ apr_pool_t *pool)
+{
+ return svn_client_merge4(source1, revision1, source2, revision2,
+ target_wcpath, depth, ignore_ancestry, force,
+ record_only, dry_run, TRUE, merge_options,
+ ctx, pool);
+}
+
+svn_error_t *
svn_client_merge2(const char *source1,
const svn_opt_revision_t *revision1,
const char *source2,
@@ -1375,7 +1397,25 @@ svn_client_merge(const char *source1,
dry_run, NULL, ctx, pool);
}
-
+svn_error_t *
+svn_client_merge_peg3(const char *source,
+ const apr_array_header_t *ranges_to_merge,
+ const svn_opt_revision_t *peg_revision,
+ const char *target_wcpath,
+ svn_depth_t depth,
+ svn_boolean_t ignore_ancestry,
+ svn_boolean_t force,
+ svn_boolean_t record_only,
+ svn_boolean_t dry_run,
+ const apr_array_header_t *merge_options,
+ svn_client_ctx_t *ctx,
+ apr_pool_t *pool)
+{
+ return svn_client_merge_peg4(source, ranges_to_merge, peg_revision,
+ target_wcpath, depth, ignore_ancestry, force,
+ record_only, dry_run, TRUE, merge_options,
+ ctx, pool);
+}
svn_error_t *
svn_client_merge_peg2(const char *source,
@@ -2039,3 +2079,18 @@ svn_client_mergeinfo_log_eligible(const
svn_depth_empty, revprops, ctx,
pool);
}
+
+/*** From relocate.c ***/
+svn_error_t *
+svn_client_relocate(const char *path,
+ const char *from_prefix,
+ const char *to_prefix,
+ svn_boolean_t recurse,
+ svn_client_ctx_t *ctx,
+ apr_pool_t *pool)
+{
+ if (! recurse)
+ svn_error_create(SVN_ERR_UNSUPPORTED_FEATURE, 0,
+ _("Non-recursive relocation not supported"));
+ return svn_client_relocate2(path, from_prefix, to_prefix, TRUE, ctx, pool);
+}
Modified: subversion/branches/py-tests-as-modules/subversion/libsvn_client/export.c
URL: http://svn.apache.org/viewvc/subversion/branches/py-tests-as-modules/subversion/libsvn_client/export.c?rev=1031230&r1=1031229&r2=1031230&view=diff
==============================================================================
--- subversion/branches/py-tests-as-modules/subversion/libsvn_client/export.c (original)
+++ subversion/branches/py-tests-as-modules/subversion/libsvn_client/export.c Thu Nov 4 20:48:21 2010
@@ -300,7 +300,6 @@ copy_versioned_files(const char *from,
const char *to_abspath;
svn_node_kind_t from_kind;
svn_depth_t node_depth;
- int j;
SVN_ERR(svn_dirent_get_absolute(&from_abspath, from, pool));
SVN_ERR(svn_dirent_get_absolute(&to_abspath, to, pool));
@@ -350,6 +349,7 @@ copy_versioned_files(const char *from,
if (from_kind == svn_node_dir)
{
apr_fileperms_t perm = APR_OS_DEFAULT;
+ int j;
/* Try to make the new directory. If this fails because the
directory already exists, check our FORCE flag to see if we
@@ -929,8 +929,8 @@ close_file(void *file_baton,
svn_error_t *
svn_client_export5(svn_revnum_t *result_rev,
- const char *from,
- const char *to,
+ const char *from_path_or_url,
+ const char *to_path,
const svn_opt_revision_t *peg_revision,
const svn_opt_revision_t *revision,
svn_boolean_t overwrite,
@@ -947,15 +947,16 @@ svn_client_export5(svn_revnum_t *result_
SVN_ERR_ASSERT(peg_revision != NULL);
SVN_ERR_ASSERT(revision != NULL);
- if (svn_path_is_url(to))
+ if (svn_path_is_url(to_path))
return svn_error_return(svn_error_createf(SVN_ERR_ILLEGAL_TARGET, NULL,
_("'%s' is not a local path"),
- to));
+ to_path));
- peg_revision = svn_cl__rev_default_to_head_or_working(peg_revision, from);
+ peg_revision = svn_cl__rev_default_to_head_or_working(peg_revision,
+ from_path_or_url);
revision = svn_cl__rev_default_to_peg(revision, peg_revision);
- if (svn_path_is_url(from) ||
+ if (svn_path_is_url(from_path_or_url) ||
! SVN_CLIENT__REVKIND_IS_LOCAL_TO_WC(revision->kind))
{
svn_revnum_t revnum;
@@ -966,14 +967,14 @@ svn_client_export5(svn_revnum_t *result_
/* Get the RA connection. */
SVN_ERR(svn_client__ra_session_from_path(&ra_session, &revnum,
- &url, from, NULL,
+ &url, from_path_or_url, NULL,
peg_revision,
revision, ctx, pool));
/* Get the repository root. */
SVN_ERR(svn_ra_get_repos_root2(ra_session, &repos_root_url, pool));
- eb->root_path = to;
+ eb->root_path = to_path;
eb->root_url = url;
eb->force = overwrite;
eb->target_revision = &edit_revision;
@@ -993,6 +994,13 @@ svn_client_export5(svn_revnum_t *result_
apr_hash_index_t *hi;
struct file_baton *fb = apr_pcalloc(pool, sizeof(*fb));
+ if (svn_path_is_empty(to_path))
+ {
+ to_path = svn_path_uri_decode(svn_uri_basename(from_path_or_url,
+ NULL), pool);
+ eb->root_path = to_path;
+ }
+
/* Since you cannot actually root an editor at a file, we
* manually drive a few functions of our editor. */
@@ -1084,19 +1092,19 @@ svn_client_export5(svn_revnum_t *result_
* So we just create the empty dir manually; but we do it via
* open_root_internal(), in order to get proper notification.
*/
- SVN_ERR(svn_io_check_path(to, &kind, pool));
+ SVN_ERR(svn_io_check_path(to_path, &kind, pool));
if (kind == svn_node_none)
SVN_ERR(open_root_internal
- (to, overwrite, ctx->notify_func2,
+ (to_path, overwrite, ctx->notify_func2,
ctx->notify_baton2, pool));
if (! ignore_externals && depth == svn_depth_infinity)
{
const char *to_abspath;
- SVN_ERR(svn_dirent_get_absolute(&to_abspath, to, pool));
+ SVN_ERR(svn_dirent_get_absolute(&to_abspath, to_path, pool));
SVN_ERR(svn_client__fetch_externals(eb->externals,
- from, to_abspath,
+ from_path_or_url, to_abspath,
repos_root_url, depth, TRUE,
native_eol, &use_sleep,
ctx, pool));
@@ -1105,7 +1113,8 @@ svn_client_export5(svn_revnum_t *result_
else if (kind == svn_node_none)
{
return svn_error_createf(SVN_ERR_RA_ILLEGAL_URL, NULL,
- _("URL '%s' doesn't exist"), from);
+ _("URL '%s' doesn't exist"),
+ from_path_or_url);
}
/* kind == svn_node_unknown not handled */
}
@@ -1113,8 +1122,8 @@ svn_client_export5(svn_revnum_t *result_
{
/* This is a working copy export. */
/* just copy the contents of the working copy into the target path. */
- SVN_ERR(copy_versioned_files(from, to, revision, overwrite,
- ignore_externals, ignore_keywords,
+ SVN_ERR(copy_versioned_files(from_path_or_url, to_path, revision,
+ overwrite, ignore_externals, ignore_keywords,
depth, native_eol, ctx, pool));
}
@@ -1122,7 +1131,7 @@ svn_client_export5(svn_revnum_t *result_
if (ctx->notify_func2)
{
svn_wc_notify_t *notify
- = svn_wc_create_notify(to,
+ = svn_wc_create_notify(to_path,
svn_wc_notify_update_completed, pool);
notify->revision = edit_revision;
(*ctx->notify_func2)(ctx->notify_baton2, notify, pool);
Modified: subversion/branches/py-tests-as-modules/subversion/libsvn_client/externals.c
URL: http://svn.apache.org/viewvc/subversion/branches/py-tests-as-modules/subversion/libsvn_client/externals.c?rev=1031230&r1=1031229&r2=1031230&view=diff
==============================================================================
--- subversion/branches/py-tests-as-modules/subversion/libsvn_client/externals.c (original)
+++ subversion/branches/py-tests-as-modules/subversion/libsvn_client/externals.c Thu Nov 4 20:48:21 2010
@@ -205,7 +205,7 @@ switch_dir_external(const char *path,
revision, svn_depth_unknown,
FALSE, FALSE, FALSE,
timestamp_sleep, TRUE,
- TRUE, ctx, subpool));
+ ctx, subpool));
svn_pool_destroy(subpool);
return SVN_NO_ERROR;
}
@@ -229,8 +229,8 @@ switch_dir_external(const char *path,
SVN_ERR(svn_ra_get_repos_root2(ra_session, &repos_root,
subpool));
- err = svn_client_relocate(path, repos_root_url, repos_root,
- TRUE, ctx, subpool);
+ err = svn_client_relocate2(path, repos_root_url, repos_root,
+ FALSE, ctx, subpool);
/* If the relocation failed because the new URL points
to another repository, then we need to relegate and
check out a new WC. */
@@ -576,7 +576,7 @@ resolve_relative_external_url(svn_wc_ext
pool,
url[2] == '/' ? "///" : "//",
svn_relpath_canonicalize(url+2, pool),
- NULL);
+ (char *)NULL);
}
else if (svn_path_is_url(url) || *url == '/')
{
@@ -697,7 +697,7 @@ resolve_relative_external_url(svn_wc_ext
scheme,
":",
url,
- NULL),
+ (char *)NULL),
pool);
return SVN_NO_ERROR;
}
Modified: subversion/branches/py-tests-as-modules/subversion/libsvn_client/info.c
URL: http://svn.apache.org/viewvc/subversion/branches/py-tests-as-modules/subversion/libsvn_client/info.c?rev=1031230&r1=1031229&r2=1031230&view=diff
==============================================================================
--- subversion/branches/py-tests-as-modules/subversion/libsvn_client/info.c (original)
+++ subversion/branches/py-tests-as-modules/subversion/libsvn_client/info.c Thu Nov 4 20:48:21 2010
@@ -167,6 +167,9 @@ build_info_for_entry(svn_info_t **info,
SVN_ERR(svn_wc__node_get_schedule(&tmpinfo->schedule, NULL,
wc_ctx, local_abspath, pool));
+ SVN_ERR(svn_wc_get_wc_root(&tmpinfo->wcroot_abspath, wc_ctx,
+ local_abspath, pool, pool));
+
/* Some random stuffs we don't have wc-ng apis for yet */
SVN_ERR(svn_wc__node_get_info_bits(&tmpinfo->text_time,
&tmpinfo->conflict_old,
@@ -289,7 +292,7 @@ push_dir_info(svn_ra_session_t *ra_sessi
URL = svn_path_url_add_component2(session_URL, name, subpool);
fs_path = svn_uri_is_child(repos_root, URL, subpool);
- fs_path = apr_pstrcat(subpool, "/", fs_path, NULL);
+ fs_path = apr_pstrcat(subpool, "/", fs_path, (char *)NULL);
fs_path = svn_path_uri_decode(fs_path, subpool);
lock = apr_hash_get(locks, fs_path, APR_HASH_KEY_STRING);
@@ -692,6 +695,8 @@ svn_info_dup(const svn_info_t *info, apr
dupinfo->conflict_wrk = apr_pstrdup(pool, info->conflict_wrk);
if (info->prejfile)
dupinfo->prejfile = apr_pstrdup(pool, info->prejfile);
+ if (info->wcroot_abspath)
+ dupinfo->wcroot_abspath = apr_pstrdup(pool, info->wcroot_abspath);
return dupinfo;
}
Modified: subversion/branches/py-tests-as-modules/subversion/libsvn_client/list.c
URL: http://svn.apache.org/viewvc/subversion/branches/py-tests-as-modules/subversion/libsvn_client/list.c?rev=1031230&r1=1031229&r2=1031230&view=diff
==============================================================================
--- subversion/branches/py-tests-as-modules/subversion/libsvn_client/list.c (original)
+++ subversion/branches/py-tests-as-modules/subversion/libsvn_client/list.c Thu Nov 4 20:48:21 2010
@@ -63,14 +63,23 @@ get_dir_contents(apr_uint32_t dirent_fie
apr_hash_t *tmpdirents;
apr_pool_t *iterpool = svn_pool_create(pool);
apr_array_header_t *array;
+ svn_error_t *err;
int i;
if (depth == svn_depth_empty)
return SVN_NO_ERROR;
- /* Get the directory's entries, but not its props. */
- SVN_ERR(svn_ra_get_dir2(ra_session, &tmpdirents, NULL, NULL,
- dir, rev, dirent_fields, pool));
+ /* Get the directory's entries, but not its props. Ignore any
+ not-authorized errors. */
+ err = svn_ra_get_dir2(ra_session, &tmpdirents, NULL, NULL,
+ dir, rev, dirent_fields, pool);
+ if (err && ((err->apr_err == SVN_ERR_RA_NOT_AUTHORIZED) ||
+ (err->apr_err == SVN_ERR_RA_DAV_FORBIDDEN)))
+ {
+ svn_error_clear(err);
+ return SVN_NO_ERROR;
+ }
+ SVN_ERR(err);
if (ctx->cancel_func)
SVN_ERR(ctx->cancel_func(ctx->cancel_baton));
Modified: subversion/branches/py-tests-as-modules/subversion/libsvn_client/locking_commands.c
URL: http://svn.apache.org/viewvc/subversion/branches/py-tests-as-modules/subversion/libsvn_client/locking_commands.c?rev=1031230&r1=1031229&r2=1031230&view=diff
==============================================================================
--- subversion/branches/py-tests-as-modules/subversion/libsvn_client/locking_commands.c (original)
+++ subversion/branches/py-tests-as-modules/subversion/libsvn_client/locking_commands.c Thu Nov 4 20:48:21 2010
@@ -182,6 +182,23 @@ organize_lock_targets(const char **commo
apr_hash_t *rel_targets_ret = apr_hash_make(pool);
apr_pool_t *subpool = svn_pool_create(pool);
svn_boolean_t url_mode;
+ svn_boolean_t wc_present = FALSE, url_present = FALSE;
+
+ /* Check to see if at least one of our paths is a working copy
+ * path or a repository url. */
+ for (i = 0; i < targets->nelts; ++i)
+ {
+ const char *target = APR_ARRAY_IDX(targets, i, const char *);
+ if (! svn_path_is_url(target))
+ wc_present = TRUE;
+ else
+ url_present = TRUE;
+ }
+
+ if (url_present && wc_present)
+ return svn_error_createf(SVN_ERR_ILLEGAL_TARGET, NULL,
+ _("Cannot mix repository and working copy "
+ "targets"));
/* All targets must be either urls or paths */
Modified: subversion/branches/py-tests-as-modules/subversion/libsvn_client/merge.c
URL: http://svn.apache.org/viewvc/subversion/branches/py-tests-as-modules/subversion/libsvn_client/merge.c?rev=1031230&r1=1031229&r2=1031230&view=diff
==============================================================================
--- subversion/branches/py-tests-as-modules/subversion/libsvn_client/merge.c (original)
+++ subversion/branches/py-tests-as-modules/subversion/libsvn_client/merge.c Thu Nov 4 20:48:21 2010
@@ -1121,8 +1121,6 @@ merge_props_changed(const char *local_di
definition, 'svn merge' shouldn't touch any data within .svn/ */
if (props->nelts)
{
- int i;
-
/* If this is a forward merge then don't add new mergeinfo to
PATH that is already part of PATH's own history, see
http://svn.haxx.se/dev/archive-2008-09/0006.shtml. If the
@@ -1150,6 +1148,8 @@ merge_props_changed(const char *local_di
is having its existing mergeinfo deleted. */
if (!merge_b->dry_run)
{
+ int i;
+
for (i = 0; i < props->nelts; ++i)
{
svn_prop_t *prop = &APR_ARRAY_IDX(props, i, svn_prop_t);
@@ -1723,13 +1723,14 @@ merge_file_added(const char *local_dir_a
copying 'yours' to 'mine', isn't enough; we need to get
the whole text-base and props installed too, just as if
we had called 'svn cp wc wc'. */
- /* ### would be nice to have cancel/notify funcs to pass */
SVN_ERR(svn_wc_add_repos_file4(
merge_b->ctx->wc_ctx, mine_abspath,
new_base_contents, new_contents,
new_base_props, new_props,
copyfrom_url, copyfrom_rev,
- NULL, NULL, NULL, NULL, subpool));
+ merge_b->ctx->cancel_func,
+ merge_b->ctx->cancel_baton,
+ subpool));
/* ### delete 'yours' ? */
}
@@ -3778,8 +3779,8 @@ filter_merged_revisions(svn_client__merg
child->remaining_ranges = svn_rangelist_dup(explicit_rangelist,
pool);
}
- }
#endif
+ }
svn_pool_destroy(subpool);
return SVN_NO_ERROR;
@@ -6596,7 +6597,6 @@ do_file_merge(svn_mergeinfo_catalog_t re
svn_merge_range_t range;
svn_mergeinfo_t target_mergeinfo;
svn_merge_range_t *conflicted_range = NULL;
- int i;
svn_boolean_t indirect = FALSE;
apr_pool_t *subpool;
svn_boolean_t is_rollback = (revision1 > revision2);
@@ -6676,6 +6676,7 @@ do_file_merge(svn_mergeinfo_catalog_t re
if (!merge_b->record_only)
{
apr_array_header_t *ranges_to_merge = remaining_ranges;
+ int i;
/* If we have ancestrally related sources and more than one
range to merge, eliminate no-op ranges before going through
@@ -8028,7 +8029,18 @@ do_directory_merge(svn_mergeinfo_catalog
apr_pool_t *pool)
{
svn_error_t *err = SVN_NO_ERROR;
+
+ /* The range defining the mergeinfo we will record to describe the merge
+ (assuming we are recording mergeinfo
+
+ Note: This may be a subset of REVISION1:REVISION2 if
+ populate_remaining_ranges() determines that some part of
+ REVISION1:REVISION2 has already been wholly merged to TARGET_ABSPATH.
+ Also, the actual editor drive(s) may be a subset of RANGE, if
+ remove_noop_subtree_ranges() and/or fix_deleted_subtree_ranges()
+ further tweak things. */
svn_merge_range_t range;
+
svn_ra_session_t *ra_session;
svn_client__merge_path_t *target_merge_path;
svn_boolean_t is_rollback = (revision1 > revision2);
@@ -8101,17 +8113,22 @@ do_directory_merge(svn_mergeinfo_catalog
if (honor_mergeinfo && !merge_b->reintegrate_merge)
{
- svn_revnum_t start_rev, end_rev;
+ svn_revnum_t new_range_start, start_rev, end_rev;
apr_pool_t *iterpool = svn_pool_create(pool);
- /* The merge target target_wcpath and/or its subtrees may not need all
+ /* The merge target TARGET_ABSPATH and/or its subtrees may not need all
of REVISION1:REVISION2 applied. So examine
NOTIFY_B->CHILDREN_WITH_MERGEINFO to find the oldest starting
revision that actually needs to be merged (for reverse merges this is
- the youngest starting revision). */
- start_rev =
- get_most_inclusive_start_rev(notify_b->children_with_mergeinfo,
- is_rollback);
+ the youngest starting revision).
+
+ We'll do this twice, right now for the start of the mergeinfo we will
+ ultimately record to describe this merge and then later for the
+ start of the actual editor drive. */
+ new_range_start = get_most_inclusive_start_rev(
+ notify_b->children_with_mergeinfo, is_rollback);
+ if (SVN_IS_VALID_REVNUM(new_range_start))
+ range.start = new_range_start;
/* Remove inoperative ranges from any subtrees' remaining_ranges
to spare the expense of noop editor drives. */
@@ -8121,16 +8138,20 @@ do_directory_merge(svn_mergeinfo_catalog
notify_b, merge_b,
pool, iterpool));
+ /* Adjust subtrees' remaining_ranges to deal with issue #3067 */
SVN_ERR(fix_deleted_subtree_ranges(url1, revision1, url2, revision2,
ra_session, notify_b, merge_b, pool));
+ /* remove_noop_subtree_ranges() and/or fix_deleted_subtree_range()
+ may have further refined the starting revision for our editor
+ drive. */
+ start_rev =
+ get_most_inclusive_start_rev(notify_b->children_with_mergeinfo,
+ is_rollback);
+
/* Is there anything to merge? */
if (SVN_IS_VALID_REVNUM(start_rev))
{
- /* Adjust range to describe the start of our most
- inclusive merge. */
- range.start = start_rev;
-
/* Now examine NOTIFY_B->CHILDREN_WITH_MERGEINFO to find the youngest
ending revision that actually needs to be merged (for reverse
merges this is the oldest starting revision). */
@@ -8170,6 +8191,33 @@ do_directory_merge(svn_mergeinfo_catalog
svn_revnum_t next_end_rev;
const char *real_url1 = url1, *real_url2 = url2;
const char *old_sess1_url = NULL, *old_sess2_url = NULL;
+ svn_merge_range_t *first_target_range = APR_ARRAY_IDX(
+ target_merge_path->remaining_ranges, 0, svn_merge_range_t *);
+
+ /* Issue #3324: Stop editor abuse! Don't call
+ drive_merge_report_editor() in such a way that we request an
+ editor with svn_client__get_diff_editor() for some rev X,
+ then call svn_ra_do_diff3() for some revision Y, and then
+ call reporter->set_path(PATH=="") to set the root revision
+ for the editor drive to revision Z where
+ (X != Z && X < Z < Y). This is bogus because the server will
+ send us the diff between X:Y but the client is expecting the
+ diff between Y:Z. See issue #3324 for full details on the
+ problems this can cause. */
+ if (first_target_range
+ && start_rev != first_target_range->start)
+ {
+ if (is_rollback)
+ {
+ if (end_rev < first_target_range->start)
+ end_rev = first_target_range->start;
+ }
+ else
+ {
+ if (end_rev > first_target_range->start)
+ end_rev = first_target_range->start;
+ }
+ }
svn_pool_clear(iterpool);
@@ -8815,6 +8863,73 @@ merge_cousins_and_supplement_mergeinfo(c
return SVN_NO_ERROR;
}
+/* Perform checks to determine whether of the working copy at TARGET_ABSPATH
+ * can safely be used as a merge target. Checks are performed according to
+ * the ALLOW_MIXED_REV, ALLOW_LOCAL_MODS, and ALLOW_SWITCHED_SUBTREES
+ * parameters. If any checks fail, raise SVN_ERR_CLIENT_NOT_READY_TO_MERGE.
+ *
+ * E.g. if all the ALLOW_* parameters are FALSE, TARGET_ABSPATH must
+ * be a single-revision, pristine, unswitched working copy.
+ * In other words, it must reflect a subtree of the repostiory as found
+ * at single revision -- although sparse checkouts are permitted. */
+static svn_error_t *
+ensure_wc_is_suitable_merge_target(const char *target_abspath,
+ svn_client_ctx_t *ctx,
+ svn_boolean_t allow_mixed_rev,
+ svn_boolean_t allow_local_mods,
+ svn_boolean_t allow_switched_subtrees,
+ apr_pool_t *scratch_pool)
+{
+ svn_wc_revision_status_t *wc_stat;
+
+ /* Avoid the following status crawl if we don't need it. */
+ if (allow_mixed_rev && allow_local_mods && allow_switched_subtrees)
+ return SVN_NO_ERROR;
+
+ /* Get a WC summary with min/max revisions set to the BASE revision. */
+ SVN_ERR(svn_wc_revision_status2(&wc_stat, ctx->wc_ctx, target_abspath, NULL,
+ FALSE, ctx->cancel_func, ctx->cancel_baton,
+ scratch_pool, scratch_pool));
+
+ if (! allow_switched_subtrees && wc_stat->switched)
+ return svn_error_create(SVN_ERR_CLIENT_NOT_READY_TO_MERGE, NULL,
+ _("Cannot merge into a working copy "
+ "with a switched subtree"));
+
+ if (! allow_local_mods && wc_stat->modified)
+ return svn_error_create(SVN_ERR_CLIENT_NOT_READY_TO_MERGE, NULL,
+ _("Cannot merge into a working copy "
+ "that has local modifications"));
+
+ if (! allow_mixed_rev)
+ {
+ if (! (SVN_IS_VALID_REVNUM(wc_stat->min_rev)
+ && SVN_IS_VALID_REVNUM(wc_stat->max_rev)))
+ {
+ svn_boolean_t is_added;
+
+ /* Allow merge into added nodes. */
+ SVN_ERR(svn_wc__node_is_added(&is_added, ctx->wc_ctx, target_abspath,
+ scratch_pool));
+ if (is_added)
+ return SVN_NO_ERROR;
+ else
+ return svn_error_create(SVN_ERR_CLIENT_NOT_READY_TO_MERGE, NULL,
+ _("Cannot determine revision of working "
+ "copy"));
+ }
+
+ if (wc_stat->min_rev != wc_stat->max_rev)
+ return svn_error_createf(SVN_ERR_CLIENT_NOT_READY_TO_MERGE, NULL,
+ _("Cannot merge into mixed-revision working "
+ "copy [%lu:%lu]; try updating first"),
+ wc_stat->min_rev, wc_stat->max_rev);
+ }
+
+ return SVN_NO_ERROR;
+}
+
+
/*-----------------------------------------------------------------------*/
/*** Public APIs ***/
@@ -8830,6 +8945,7 @@ merge_locked(const char *source1,
svn_boolean_t force,
svn_boolean_t record_only,
svn_boolean_t dry_run,
+ svn_boolean_t allow_mixed_rev,
const apr_array_header_t *merge_options,
svn_client_ctx_t *ctx,
apr_pool_t *scratch_pool)
@@ -8905,6 +9021,12 @@ merge_locked(const char *source1,
_("Merge target '%s' does not exist in the "
"working copy"), target_abspath));
+
+ /* Do not allow merges into mixed-revision working copies. */
+ SVN_ERR(ensure_wc_is_suitable_merge_target(target_abspath, ctx,
+ allow_mixed_rev, TRUE, TRUE,
+ scratch_pool));
+
/* Determine the working copy target's repository root URL. */
working_rev.kind = svn_opt_revision_working;
SVN_ERR(svn_client__get_repos_root(&wc_repos_root, target_abspath,
@@ -9103,6 +9225,7 @@ struct merge_baton {
svn_boolean_t force;
svn_boolean_t record_only;
svn_boolean_t dry_run;
+ svn_boolean_t allow_mixed_rev;
const apr_array_header_t *merge_options;
svn_client_ctx_t *ctx;
};
@@ -9116,7 +9239,8 @@ merge_cb(void *baton, apr_pool_t *result
SVN_ERR(merge_locked(b->source1, b->revision1, b->source2, b->revision2,
b->target_abspath, b->depth, b->ignore_ancestry,
b->force, b->record_only, b->dry_run,
- b->merge_options, b->ctx, scratch_pool));
+ b->allow_mixed_rev, b->merge_options, b->ctx,
+ scratch_pool));
return SVN_NO_ERROR;
}
@@ -9144,7 +9268,7 @@ get_target_and_lock_abspath(const char *
}
svn_error_t *
-svn_client_merge3(const char *source1,
+svn_client_merge4(const char *source1,
const svn_opt_revision_t *revision1,
const char *source2,
const svn_opt_revision_t *revision2,
@@ -9154,6 +9278,7 @@ svn_client_merge3(const char *source1,
svn_boolean_t force,
svn_boolean_t record_only,
svn_boolean_t dry_run,
+ svn_boolean_t allow_mixed_rev,
const apr_array_header_t *merge_options,
svn_client_ctx_t *ctx,
apr_pool_t *pool)
@@ -9174,6 +9299,7 @@ svn_client_merge3(const char *source1,
baton.force = force;
baton.record_only = record_only;
baton.dry_run = dry_run;
+ baton.allow_mixed_rev = allow_mixed_rev;
baton.merge_options = merge_options;
baton.ctx = ctx;
@@ -9188,45 +9314,6 @@ svn_client_merge3(const char *source1,
}
-/* If TARGET_WCPATH does not reflect a single-revision, pristine,
- unswitched working copy -- in other words, a subtree found in a
- single revision (although sparse checkouts are permitted) -- raise
- SVN_ERR_CLIENT_NOT_READY_TO_MERGE. */
-static svn_error_t *
-ensure_wc_reflects_repository_subtree(const char *target_abspath,
- svn_client_ctx_t *ctx,
- apr_pool_t *scratch_pool)
-{
- svn_wc_revision_status_t *wc_stat;
-
- /* Get a WC summary with min/max revisions set to the BASE revision. */
- SVN_ERR(svn_wc_revision_status2(&wc_stat, ctx->wc_ctx, target_abspath, NULL,
- FALSE, ctx->cancel_func, ctx->cancel_baton,
- scratch_pool, scratch_pool));
-
- if (wc_stat->switched)
- return svn_error_create(SVN_ERR_CLIENT_NOT_READY_TO_MERGE, NULL,
- _("Cannot reintegrate into a working copy "
- "with a switched subtree"));
-
- if (wc_stat->modified)
- return svn_error_create(SVN_ERR_CLIENT_NOT_READY_TO_MERGE, NULL,
- _("Cannot reintegrate into a working copy "
- "that has local modifications"));
-
- if (! (SVN_IS_VALID_REVNUM(wc_stat->min_rev)
- && SVN_IS_VALID_REVNUM(wc_stat->max_rev)))
- return svn_error_create(SVN_ERR_CLIENT_NOT_READY_TO_MERGE, NULL,
- _("Cannot determine revision of working copy"));
-
- if (wc_stat->min_rev != wc_stat->max_rev)
- return svn_error_create(SVN_ERR_CLIENT_NOT_READY_TO_MERGE, NULL,
- _("Cannot reintegrate into mixed-revision "
- "working copy; try updating first"));
-
- return SVN_NO_ERROR;
-}
-
/* Check if mergeinfo for a given path is described explicitly or via
inheritance in a mergeinfo catalog.
@@ -10174,8 +10261,11 @@ merge_reintegrate_locked(const char *sou
svn_dirent_local_style(target_abspath,
scratch_pool));
- SVN_ERR(ensure_wc_reflects_repository_subtree(target_abspath, ctx,
- scratch_pool));
+ /* A reintegrate merge requires the merge target to reflect a subtree
+ * of the repository as found at a single revision. */
+ SVN_ERR(ensure_wc_is_suitable_merge_target(target_abspath, ctx,
+ FALSE, FALSE, FALSE,
+ scratch_pool));
SVN_ERR(svn_wc__node_get_base_rev(&target_base_rev, ctx->wc_ctx,
target_abspath, scratch_pool));
@@ -10391,6 +10481,7 @@ merge_peg_locked(const char *source,
svn_boolean_t force,
svn_boolean_t record_only,
svn_boolean_t dry_run,
+ svn_boolean_t allow_mixed_rev,
const apr_array_header_t *merge_options,
svn_client_ctx_t *ctx,
apr_pool_t *scratch_pool)
@@ -10432,6 +10523,10 @@ merge_peg_locked(const char *source,
_("Merge target '%s' does not exist in the "
"working copy"), target_abspath));
+ SVN_ERR(ensure_wc_is_suitable_merge_target(target_abspath, ctx,
+ allow_mixed_rev, TRUE, TRUE,
+ scratch_pool));
+
/* Determine the working copy target's repository root URL. */
working_rev.kind = svn_opt_revision_working;
SVN_ERR(svn_client__get_repos_root(&wc_repos_root, target_abspath,
@@ -10494,6 +10589,7 @@ struct merge_peg_baton {
svn_boolean_t force;
svn_boolean_t record_only;
svn_boolean_t dry_run;
+ svn_boolean_t allow_mixed_rev;
const apr_array_header_t *merge_options;
svn_client_ctx_t *ctx;
};
@@ -10507,13 +10603,14 @@ merge_peg_cb(void *baton, apr_pool_t *re
SVN_ERR(merge_peg_locked(b->source, b->ranges_to_merge, b->peg_revision,
b->target_abspath, b->depth, b->ignore_ancestry,
b->force, b->record_only, b->dry_run,
- b->merge_options, b->ctx, scratch_pool));
+ b->allow_mixed_rev, b->merge_options, b->ctx,
+ scratch_pool));
return SVN_NO_ERROR;
}
svn_error_t *
-svn_client_merge_peg3(const char *source,
+svn_client_merge_peg4(const char *source,
const apr_array_header_t *ranges_to_merge,
const svn_opt_revision_t *peg_revision,
const char *target_wcpath,
@@ -10522,6 +10619,7 @@ svn_client_merge_peg3(const char *source
svn_boolean_t force,
svn_boolean_t record_only,
svn_boolean_t dry_run,
+ svn_boolean_t allow_mixed_rev,
const apr_array_header_t *merge_options,
svn_client_ctx_t *ctx,
apr_pool_t *pool)
@@ -10545,6 +10643,7 @@ svn_client_merge_peg3(const char *source
baton.force = force;
baton.record_only = record_only;
baton.dry_run = dry_run;
+ baton.allow_mixed_rev = allow_mixed_rev;
baton.merge_options = merge_options;
baton.ctx = ctx;
Modified: subversion/branches/py-tests-as-modules/subversion/libsvn_client/mergeinfo.c
URL: http://svn.apache.org/viewvc/subversion/branches/py-tests-as-modules/subversion/libsvn_client/mergeinfo.c?rev=1031230&r1=1031229&r2=1031230&view=diff
==============================================================================
--- subversion/branches/py-tests-as-modules/subversion/libsvn_client/mergeinfo.c (original)
+++ subversion/branches/py-tests-as-modules/subversion/libsvn_client/mergeinfo.c Thu Nov 4 20:48:21 2010
@@ -672,7 +672,7 @@ svn_client__mergeinfo_from_segments(svn_
continue;
/* Prepend a leading slash to our path. */
- source_path = apr_pstrcat(pool, "/", segment->path, NULL);
+ source_path = apr_pstrcat(pool, "/", segment->path, (char *)NULL);
/* See if we already stored ranges for this path. If not, make
a new list. */
@@ -1258,11 +1258,12 @@ static svn_mergeinfo_t
find_nearest_ancestor(const apr_array_header_t *depth_first_catalog_index,
const char *abs_repos_path)
{
- int i;
int ancestor_index = -1;
if (depth_first_catalog_index)
{
+ int i;
+
for (i = 0; i < depth_first_catalog_index->nelts; i++)
{
svn_sort__item_t item = APR_ARRAY_IDX(depth_first_catalog_index, i,
Modified: subversion/branches/py-tests-as-modules/subversion/libsvn_client/patch.c
URL: http://svn.apache.org/viewvc/subversion/branches/py-tests-as-modules/subversion/libsvn_client/patch.c?rev=1031230&r1=1031229&r2=1031230&view=diff
==============================================================================
--- subversion/branches/py-tests-as-modules/subversion/libsvn_client/patch.c (original)
+++ subversion/branches/py-tests-as-modules/subversion/libsvn_client/patch.c Thu Nov 4 20:48:21 2010
@@ -346,9 +346,7 @@ 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.
- * ### Do we need to check for empty paths here, shouldn't the parser
- * ### guarentee that the paths returned are non-empty? */
+ /* We allow properties to be set on the wc root dir. */
if (! prop_changes_only && target->canon_path_from_patchfile[0] == '\0')
{
/* An empty patch target path? What gives? Skip this. */
@@ -498,7 +496,7 @@ init_prop_target(prop_patch_target_t **p
new_prop_target->content_info = content_info;
err = svn_wc_prop_get2(&value, wc_ctx, local_abspath, prop_name,
- result_pool, scratch_pool);
+ result_pool, scratch_pool);
if (err)
{
if (err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND)
@@ -528,12 +526,40 @@ init_prop_target(prop_patch_target_t **p
return SVN_NO_ERROR;
}
+/* Return a suitable filename for the target of PATCH.
+ * Examine the ``old'' and ``new'' file names, and choose the file name
+ * with the fewest path components, the shortest basename, and the shortest
+ * total file name length (in that order). In case of a tie, return the new
+ * filename. This heuristic is also used by Larry Wall's UNIX patch (except
+ * that it prompts for a filename in case of a tie). */
+static const char *
+choose_target_filename(const svn_patch_t *patch)
+{
+ apr_size_t old;
+ apr_size_t new;
+
+ old = svn_path_component_count(patch->old_filename);
+ new = svn_path_component_count(patch->new_filename);
+
+ if (old == new)
+ {
+ old = strlen(svn_dirent_basename(patch->old_filename, NULL));
+ new = strlen(svn_dirent_basename(patch->new_filename, NULL));
+
+ if (old == new)
+ {
+ old = strlen(patch->old_filename);
+ new = strlen(patch->new_filename);
+ }
+ }
+
+ return (old < new) ? patch->old_filename : patch->new_filename;
+}
+
/* 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
* which should be stripped from target paths in the patch.
- * OLD_PATCH_TARGET_NAMES indicates whether the old target's name parsed
- * from the patch file should be preferred over the new target's name.
* The patch target structure is allocated in RESULT_POOL, but if the target
* should be skipped, PATCH_TARGET->SKIPPED is set and the target should be
* treated as not fully initialized, e.g. the caller should not not do any
@@ -545,9 +571,7 @@ static svn_error_t *
init_patch_target(patch_target_t **patch_target,
const svn_patch_t *patch,
const char *base_dir,
- svn_wc_context_t *wc_ctx,
- int strip_count,
- svn_boolean_t old_patch_target_names,
+ svn_wc_context_t *wc_ctx, int strip_count,
svn_boolean_t remove_tempfiles,
apr_pool_t *result_pool, apr_pool_t *scratch_pool)
{
@@ -593,8 +617,7 @@ init_patch_target(patch_target_t **patch
target->prop_targets = apr_hash_make(result_pool);
target->pool = result_pool;
- SVN_ERR(resolve_target_path(target, old_patch_target_names ?
- patch->old_filename : patch->new_filename,
+ SVN_ERR(resolve_target_path(target, choose_target_filename(patch),
base_dir, strip_count, prop_changes_only,
wc_ctx, result_pool, scratch_pool));
if (! target->skipped)
@@ -631,13 +654,16 @@ init_patch_target(patch_target_t **patch
scratch_pool));
}
- /* ### Is it ok to set target->added here? Isn't the target supposed to
- * ### be marked as added after it's been proven that it can be added?
- * ### One alternative is to include a git_added flag. Or maybe we
- * ### should have kept the patch field in patch_target_t? Then we
- * ### could have checked for target->patch->operation == added */
+ /* ### Is it ok to set the operation of the target already here? Isn't
+ * ### the target supposed to be marked with an operation after we have
+ * ### determined that the changes will apply cleanly to the WC? Maybe
+ * ### we should have kept the patch field in patch_target_t to be
+ * ### able to distinguish between 'what the patch says we should do'
+ * ### and 'what we can do with the given state of our WC'. */
if (patch->operation == svn_diff_op_added)
target->added = TRUE;
+ else if (patch->operation == svn_diff_op_deleted)
+ target->deleted = TRUE;
SVN_ERR(svn_stream_open_unique(&patched_raw,
&target->patched_path, NULL,
@@ -862,59 +888,41 @@ match_hunk(svn_boolean_t *matched, targe
NULL, FALSE,
content_info->keywords, FALSE,
iterpool));
- lines_read++;
SVN_ERR(read_line(content_info, &target_line, iterpool, iterpool));
- if (! hunk_eof)
+
+ lines_read++;
+
+ /* If the last line doesn't have a newline, we get EOF but still
+ * have a non-empty line to compare. */
+ if ((hunk_eof && hunk_line->len == 0) ||
+ (content_info->eof && *target_line == 0))
+ break;
+
+ /* Leading/trailing fuzzy lines always match. */
+ if ((lines_read <= fuzz && leading_context > fuzz) ||
+ (lines_read > hunk_length - fuzz && trailing_context > fuzz))
+ lines_matched = TRUE;
+ else
{
- if (lines_read <= fuzz && leading_context > fuzz)
- lines_matched = TRUE;
- else if (lines_read > hunk_length - fuzz &&
- trailing_context > fuzz)
- lines_matched = TRUE;
- else
+ if (ignore_whitespace)
{
- if (ignore_whitespace)
- {
- char *stripped_hunk_line = apr_pstrdup(pool,
- hunk_line_translated);
- char *stripped_target_line = apr_pstrdup(pool, target_line);
-
- apr_collapse_spaces(stripped_hunk_line,
- hunk_line_translated);
- apr_collapse_spaces(stripped_target_line, target_line);
- lines_matched = ! strcmp(stripped_hunk_line,
- stripped_target_line);
- }
- else
- lines_matched = ! strcmp(hunk_line_translated, target_line);
+ char *hunk_line_trimmed;
+ char *target_line_trimmed;
+
+ hunk_line_trimmed = apr_pstrdup(iterpool, hunk_line_translated);
+ target_line_trimmed = apr_pstrdup(iterpool, target_line);
+ apr_collapse_spaces(hunk_line_trimmed, hunk_line_trimmed);
+ apr_collapse_spaces(target_line_trimmed, target_line_trimmed);
+ lines_matched = ! strcmp(hunk_line_trimmed, target_line_trimmed);
}
+ else
+ lines_matched = ! strcmp(hunk_line_translated, target_line);
}
}
- while (lines_matched && ! (hunk_eof || content_info->eof));
+ while (lines_matched);
- if (hunk_eof)
- *matched = lines_matched;
- else if (content_info->eof)
- {
- /* If the target has no newline at end-of-file, we get an EOF
- * indication for the target earlier than we do get it for the hunk. */
- if (match_modified)
- SVN_ERR(svn_diff_hunk_readline_modified_text(hunk, &hunk_line,
- NULL, &hunk_eof,
- iterpool, iterpool));
- else
- SVN_ERR(svn_diff_hunk_readline_original_text(hunk, &hunk_line,
- NULL, &hunk_eof,
- iterpool, iterpool));
+ *matched = lines_matched && hunk_eof && hunk_line->len == 0;
- /* When comparing modified text we require that all lines match, else
- * a hunk that adds a newline at the end will be treated as already
- * applied even if it isn't. */
- if (! match_modified && hunk_line->len == 0 && hunk_eof)
- *matched = lines_matched;
- else
- *matched = FALSE;
- }
SVN_ERR(seek_to_line(content_info, saved_line, iterpool));
svn_pool_destroy(iterpool);
@@ -954,7 +962,6 @@ scan_for_match(svn_linenum_t *matched_li
! content_info->eof)
{
svn_boolean_t matched;
- int i;
svn_pool_clear(iterpool);
@@ -966,6 +973,7 @@ scan_for_match(svn_linenum_t *matched_li
if (matched)
{
svn_boolean_t taken = FALSE;
+ int i;
/* Don't allow hunks to match at overlapping locations. */
for (i = 0; i < content_info->hunks->nelts; i++)
@@ -1160,54 +1168,55 @@ get_hunk_info(hunk_info_t **hi, patch_ta
else if (original_start > 0 && content_info->stream)
{
svn_linenum_t saved_line = content_info->current_line;
- svn_linenum_t modified_start;
- /* Check if the hunk is already applied.
- * We only check for an exact match here, and don't bother checking
- * for already applied patches with offset/fuzz, because such a
- * check would be ambiguous. */
- if (fuzz == 0)
+ /* Scan for a match at the line where the hunk thinks it
+ * should be going. */
+ SVN_ERR(seek_to_line(content_info, original_start, scratch_pool));
+ if (content_info->current_line != original_start)
{
- modified_start = svn_diff_hunk_get_modified_start(hunk);
- if (modified_start == 0)
- {
- /* Patch wants to delete the file. */
- already_applied = target->locally_deleted;
- }
- else
- {
- SVN_ERR(seek_to_line(content_info, modified_start,
- scratch_pool));
- SVN_ERR(scan_for_match(&matched_line, content_info,
- hunk, TRUE,
- modified_start + 1,
- fuzz, ignore_whitespace, TRUE,
- cancel_func, cancel_baton,
- scratch_pool));
- already_applied = (matched_line == modified_start);
- }
+ /* Seek failed. */
+ matched_line = 0;
}
else
- already_applied = FALSE;
+ SVN_ERR(scan_for_match(&matched_line, content_info, hunk, TRUE,
+ original_start + 1, fuzz,
+ ignore_whitespace, FALSE,
+ cancel_func, cancel_baton,
+ scratch_pool));
- if (! already_applied)
+ if (matched_line != original_start)
{
- /* Scan for a match at the line where the hunk thinks it
- * should be going. */
- SVN_ERR(seek_to_line(content_info, original_start, scratch_pool));
- if (content_info->current_line != original_start)
+ /* Check if the hunk is already applied.
+ * We only check for an exact match here, and don't bother checking
+ * for already applied patches with offset/fuzz, because such a
+ * check would be ambiguous. */
+ if (fuzz == 0)
{
- /* Seek failed. */
- matched_line = 0;
+ svn_linenum_t modified_start;
+
+ modified_start = svn_diff_hunk_get_modified_start(hunk);
+ if (modified_start == 0)
+ {
+ /* Patch wants to delete the file. */
+ already_applied = target->locally_deleted;
+ }
+ else
+ {
+ SVN_ERR(seek_to_line(content_info, modified_start,
+ scratch_pool));
+ SVN_ERR(scan_for_match(&matched_line, content_info,
+ hunk, TRUE,
+ modified_start + 1,
+ fuzz, ignore_whitespace, TRUE,
+ cancel_func, cancel_baton,
+ scratch_pool));
+ already_applied = (matched_line == modified_start);
+ }
}
else
- SVN_ERR(scan_for_match(&matched_line, content_info, hunk, TRUE,
- original_start + 1, fuzz,
- ignore_whitespace, FALSE,
- cancel_func, cancel_baton,
- scratch_pool));
+ already_applied = FALSE;
- if (matched_line != original_start)
+ if (! already_applied)
{
/* Scan the whole file again from the start. */
SVN_ERR(seek_to_line(content_info, 1, scratch_pool));
@@ -1252,24 +1261,6 @@ get_hunk_info(hunk_info_t **hi, patch_ta
return SVN_NO_ERROR;
}
-/* Attempt to write LEN bytes of DATA to STREAM, the underlying file
- * of which is at ABSPATH. Fail if not all bytes could be written to
- * the stream. Do temporary allocations in POOL. */
-static svn_error_t *
-try_stream_write(svn_stream_t *stream, const char *abspath,
- const char *data, apr_size_t len, apr_pool_t *pool)
-{
- apr_size_t written;
-
- written = len;
- SVN_ERR(svn_stream_write(stream, data, &written));
- if (written != len)
- return svn_error_createf(SVN_ERR_IO_WRITE_ERROR, NULL,
- _("Error writing to '%s'"),
- svn_dirent_local_style(abspath, pool));
- return SVN_NO_ERROR;
-}
-
/* Copy lines to the patched stream until the specified LINE has been
* reached. Indicate in *EOF whether end-of-file was encountered while
* reading from the target.
@@ -1286,28 +1277,29 @@ copy_lines_to_target(target_content_info
&& ! content_info->eof)
{
const char *target_line;
+ apr_size_t len;
svn_pool_clear(iterpool);
SVN_ERR(read_line(content_info, &target_line, iterpool, iterpool));
if (! content_info->eof)
target_line = apr_pstrcat(iterpool, target_line, content_info->eol_str,
- NULL);
-
- SVN_ERR(try_stream_write(content_info->patched, patched_path,
- target_line, strlen(target_line), iterpool));
+ (char *)NULL);
+ len = strlen(target_line);
+ SVN_ERR(svn_stream_write(content_info->patched, target_line, &len));
}
svn_pool_destroy(iterpool);
return SVN_NO_ERROR;
}
-/* Write the diff text of the hunk described by HI to the
- * reject stream of CONTENT_INFO, and mark TARGET as having had rejects.
+/* Write the diff text of HUNK to the reject stream of CONTENT_INFO,
+ * and mark TARGET as having had rejects.
* Do temporary allocations in POOL. */
static svn_error_t *
reject_hunk(patch_target_t *target, target_content_info_t *content_info,
- hunk_info_t *hi, const char *prop_name, apr_pool_t *pool)
+ const svn_diff_hunk_t *hunk, const char *prop_name,
+ apr_pool_t *pool)
{
const char *hunk_header;
apr_size_t len;
@@ -1328,18 +1320,18 @@ reject_hunk(patch_target_t *target, targ
/* ### What about just setting a variable to either "@@" or "##",
* ### and merging with the else clause below? */
hunk_header = apr_psprintf(pool, "## -%lu,%lu +%lu,%lu ##%s",
- svn_diff_hunk_get_original_start(hi->hunk),
- svn_diff_hunk_get_original_length(hi->hunk),
- svn_diff_hunk_get_modified_start(hi->hunk),
- svn_diff_hunk_get_modified_length(hi->hunk),
+ svn_diff_hunk_get_original_start(hunk),
+ svn_diff_hunk_get_original_length(hunk),
+ svn_diff_hunk_get_modified_start(hunk),
+ svn_diff_hunk_get_modified_length(hunk),
APR_EOL_STR);
}
else
hunk_header = apr_psprintf(pool, "@@ -%lu,%lu +%lu,%lu @@%s",
- svn_diff_hunk_get_original_start(hi->hunk),
- svn_diff_hunk_get_original_length(hi->hunk),
- svn_diff_hunk_get_modified_start(hi->hunk),
- svn_diff_hunk_get_modified_length(hi->hunk),
+ svn_diff_hunk_get_original_start(hunk),
+ svn_diff_hunk_get_original_length(hunk),
+ svn_diff_hunk_get_modified_start(hunk),
+ svn_diff_hunk_get_modified_length(hunk),
APR_EOL_STR);
len = strlen(hunk_header);
SVN_ERR(svn_stream_write(content_info->reject, hunk_header, &len));
@@ -1352,17 +1344,22 @@ reject_hunk(patch_target_t *target, targ
svn_pool_clear(iterpool);
- SVN_ERR(svn_diff_hunk_readline_diff_text(hi->hunk, &hunk_line, &eol_str,
+ SVN_ERR(svn_diff_hunk_readline_diff_text(hunk, &hunk_line, &eol_str,
&eof, iterpool, iterpool));
if (! eof)
{
if (hunk_line->len >= 1)
- SVN_ERR(try_stream_write(content_info->reject, target->reject_path,
- hunk_line->data, hunk_line->len,
- iterpool));
+ {
+ len = hunk_line->len;
+ SVN_ERR(svn_stream_write(content_info->reject, hunk_line->data,
+ &len));
+ }
+
if (eol_str)
- SVN_ERR(try_stream_write(content_info->reject, target->reject_path,
- eol_str, strlen(eol_str), iterpool));
+ {
+ len = strlen(eol_str);
+ SVN_ERR(svn_stream_write(content_info->reject, eol_str, &len));
+ }
}
}
while (! eof);
@@ -1411,7 +1408,7 @@ apply_hunk(patch_target_t *target, targe
{
/* Seek failed, reject this hunk. */
hi->rejected = TRUE;
- SVN_ERR(reject_hunk(target, content_info, hi, prop_name, pool));
+ SVN_ERR(reject_hunk(target, content_info, hi->hunk, prop_name, pool));
return SVN_NO_ERROR;
}
}
@@ -1435,11 +1432,15 @@ apply_hunk(patch_target_t *target, targe
if (! eof && lines_read > hi->fuzz &&
lines_read <= svn_diff_hunk_get_modified_length(hi->hunk) - hi->fuzz)
{
+ apr_size_t len;
+
if (hunk_line->len >= 1)
- SVN_ERR(try_stream_write(content_info->patched,
- target->patched_path,
- hunk_line->data, hunk_line->len,
- iterpool));
+ {
+ len = hunk_line->len;
+ SVN_ERR(svn_stream_write(content_info->patched, hunk_line->data,
+ &len));
+ }
+
if (eol_str)
{
/* Use the EOL as it was read from the patch file,
@@ -1447,9 +1448,8 @@ apply_hunk(patch_target_t *target, targe
if (content_info->eol_style != svn_subst_eol_style_none)
eol_str = content_info->eol_str;
- SVN_ERR(try_stream_write(content_info->patched,
- target->patched_path, eol_str,
- strlen(eol_str), iterpool));
+ len = strlen(eol_str);
+ SVN_ERR(svn_stream_write(content_info->patched, eol_str, &len));
}
}
}
@@ -1619,31 +1619,30 @@ close_target_streams(const patch_target_
apr_hash_index_t *hi;
target_content_info_t *prop_content_info;
- /* First the streams belonging to properties .. */
- for (hi = apr_hash_first(pool, target->prop_targets);
- hi;
- hi = apr_hash_next(hi))
- {
- prop_patch_target_t *prop_target;
- prop_target = svn__apr_hash_index_val(hi);
- prop_content_info = prop_target->content_info;
-
- /* ### If the prop did not exist pre-patching we'll not have a
- * ### stream to read from. Find a better way to store info on
- * ### the existence of the target prop. */
- if (prop_content_info->stream)
- SVN_ERR(svn_stream_close(prop_content_info->stream));
+ /* First the streams belonging to properties .. */
+ for (hi = apr_hash_first(pool, target->prop_targets);
+ hi;
+ hi = apr_hash_next(hi))
+ {
+ prop_patch_target_t *prop_target;
+ prop_target = svn__apr_hash_index_val(hi);
+ prop_content_info = prop_target->content_info;
- SVN_ERR(svn_stream_close(prop_content_info->patched));
- }
+ /* ### If the prop did not exist pre-patching we'll not have a
+ * ### stream to read from. Find a better way to store info on
+ * ### the existence of the target prop. */
+ if (prop_content_info->stream)
+ SVN_ERR(svn_stream_close(prop_content_info->stream));
+ SVN_ERR(svn_stream_close(prop_content_info->patched));
+ }
- /* .. And then streams associted with the file. The reject stream is
- * shared between all target_content_info structures. */
+ /* .. and then streams associated with the file.
+ * ### We're not closing the reject stream -- it still needed and
+ * ### will be closed later in write_out_rejected_hunks(). */
if (target->kind_on_disk == svn_node_file)
SVN_ERR(svn_stream_close(target->content_info->stream));
SVN_ERR(svn_stream_close(target->content_info->patched));
- SVN_ERR(svn_stream_close(target->content_info->reject));
return SVN_NO_ERROR;
}
@@ -1654,8 +1653,6 @@ close_target_streams(const patch_target_
* in RESULT_POOL. Use WC_CTX as the working copy context.
* STRIP_COUNT specifies the number of leading path components
* which should be stripped from target paths in the patch.
- * OLD_PATCH_TARGET_NAMES indicates whether the old filename parsed
- * from the patch file should be preferred over the new filename.
* REMOVE_TEMPFILES, PATCH_FUNC, and PATCH_BATON as in svn_client_patch().
* IGNORE_WHITESPACE tells whether whitespace should be considered when
* doing the matching.
@@ -1665,7 +1662,6 @@ static svn_error_t *
apply_one_patch(patch_target_t **patch_target, svn_patch_t *patch,
const char *abs_wc_path, svn_wc_context_t *wc_ctx,
int strip_count,
- svn_boolean_t old_patch_target_names,
svn_boolean_t ignore_whitespace,
svn_boolean_t remove_tempfiles,
svn_client_patch_func_t patch_func,
@@ -1680,8 +1676,7 @@ apply_one_patch(patch_target_t **patch_t
static const int MAX_FUZZ = 2;
apr_hash_index_t *hash_index;
- SVN_ERR(init_patch_target(&target, patch, abs_wc_path, wc_ctx,
- strip_count, old_patch_target_names,
+ SVN_ERR(init_patch_target(&target, patch, abs_wc_path, wc_ctx, strip_count,
remove_tempfiles, result_pool, scratch_pool));
if (target->skipped)
{
@@ -1744,7 +1739,7 @@ apply_one_patch(patch_target_t **patch_t
if (hi->already_applied)
continue;
else if (hi->rejected)
- SVN_ERR(reject_hunk(target, target->content_info, hi,
+ SVN_ERR(reject_hunk(target, target->content_info, hi->hunk,
NULL /* prop_name */,
iterpool));
else
@@ -1833,7 +1828,7 @@ apply_one_patch(patch_target_t **patch_t
if (hi->already_applied)
continue;
else if (hi->rejected)
- SVN_ERR(reject_hunk(target, prop_target->content_info, hi,
+ SVN_ERR(reject_hunk(target, prop_target->content_info, hi->hunk,
prop_target->name,
iterpool));
else
@@ -2047,14 +2042,13 @@ create_missing_parents(patch_target_t *t
* to version control. Allow cancellation since we
* have not modified the working copy yet for this
* target. */
- SVN_ERR(svn_wc_add4(ctx->wc_ctx, local_abspath,
- svn_depth_infinity,
- NULL, SVN_INVALID_REVNUM,
- ctx->cancel_func,
- ctx->cancel_baton,
- ctx->notify_func2,
- ctx->notify_baton2,
- iterpool));
+
+ if (ctx->cancel_func)
+ SVN_ERR(ctx->cancel_func(ctx->cancel_baton));
+
+ SVN_ERR(svn_wc_add_from_disk(ctx->wc_ctx, local_abspath,
+ ctx->notify_func2, ctx->notify_baton2,
+ iterpool));
}
}
}
@@ -2132,12 +2126,10 @@ install_patched_target(patch_target_t *t
/* The target file didn't exist previously,
* so add it to version control.
* Suppress notification, we'll do that later (and also
- * during dry-run). Also suppress cancellation because
+ * during dry-run). Don't allow cancellation because
* we'd rather notify about what we did before aborting. */
- SVN_ERR(svn_wc_add4(ctx->wc_ctx, target->local_abspath,
- svn_depth_infinity,
- NULL, SVN_INVALID_REVNUM,
- NULL, NULL, NULL, NULL, pool));
+ SVN_ERR(svn_wc_add_from_disk(ctx->wc_ctx, target->local_abspath,
+ NULL, NULL, pool));
}
/* Restore the target's executable bit if necessary. */
@@ -2159,6 +2151,8 @@ write_out_rejected_hunks(patch_target_t
svn_boolean_t dry_run,
apr_pool_t *pool)
{
+ SVN_ERR(svn_stream_close(target->content_info->reject));
+
if (! dry_run && (target->had_rejects || target->had_prop_rejects))
{
/* Write out rejected hunks, if any. */
@@ -2182,14 +2176,6 @@ install_patched_prop_targets(patch_targe
apr_hash_index_t *hi;
apr_pool_t *iterpool;
- if (dry_run)
- {
- if (! target->has_text_changes && target->kind_on_disk == svn_node_none)
- target->added = TRUE;
-
- return SVN_NO_ERROR;
- }
-
iterpool = svn_pool_create(scratch_pool);
for (hi = apr_hash_first(scratch_pool, target->prop_targets);
@@ -2201,19 +2187,22 @@ install_patched_prop_targets(patch_targe
svn_stream_t *patched_stream;
svn_stringbuf_t *line;
svn_stringbuf_t *prop_content;
+ const svn_string_t *prop_val;
const char *eol_str;
svn_boolean_t eof;
+ svn_error_t *err;
svn_pool_clear(iterpool);
/* For a deleted prop we only set the value to NULL. */
if (prop_target->operation == svn_diff_op_deleted)
{
- SVN_ERR(svn_wc_prop_set4(ctx->wc_ctx, target->local_abspath,
- prop_target->name, NULL,
- TRUE /* skip_checks */,
- NULL, NULL, /* suppress notification */
- iterpool));
+ if (! dry_run)
+ SVN_ERR(svn_wc_prop_set4(ctx->wc_ctx, target->local_abspath,
+ prop_target->name, NULL,
+ TRUE /* skip_checks */,
+ NULL, NULL, /* suppress notification */
+ iterpool));
continue;
}
@@ -2257,31 +2246,73 @@ install_patched_prop_targets(patch_targe
&& target->kind_on_disk == svn_node_none
&& ! target->added)
{
- SVN_ERR(svn_io_file_create(target->local_abspath, "", scratch_pool));
- SVN_ERR(svn_wc_add4(ctx->wc_ctx, target->local_abspath,
- svn_depth_infinity,
- NULL, SVN_INVALID_REVNUM,
- ctx->cancel_func,
- ctx->cancel_baton,
- NULL, NULL, /* suppress notification */
- iterpool));
+ if (! dry_run)
+ {
+ SVN_ERR(svn_io_file_create(target->local_abspath, "",
+ scratch_pool));
+ if (ctx->cancel_func)
+ SVN_ERR(ctx->cancel_func(ctx->cancel_baton));
+ SVN_ERR(svn_wc_add_from_disk(ctx->wc_ctx, target->local_abspath,
+ /* suppress notification */
+ NULL, NULL,
+ iterpool));
+ }
target->added = TRUE;
}
- /* ### How should we handle SVN_ERR_ILLEGAL_TARGET and
- * ### SVN_ERR_BAD_MIME_TYPE?
- *
- * ### stsp: I'd say reject the property hunk.
- * ### We should verify all modified prop hunk texts using
- * ### svn_wc_canonicalize_svn_prop() before starting the
- * ### patching process, to reject them as early as possible. */
- SVN_ERR(svn_wc_prop_set4(ctx->wc_ctx, target->local_abspath,
- prop_target->name,
- svn_string_create_from_buf(prop_content,
- iterpool),
- TRUE /* skip_checks */,
- NULL, NULL,
- iterpool));
+ /* Attempt to set the property, and reject all hunks if this fails. */
+ prop_val = svn_string_create_from_buf(prop_content, iterpool);
+ if (dry_run)
+ {
+ const svn_string_t *canon_propval;
+
+ err = svn_wc_canonicalize_svn_prop(&canon_propval,
+ prop_target->name,
+ prop_val, target->local_abspath,
+ target->db_kind,
+ TRUE, /* ### Skipping checks */
+ NULL, NULL,
+ iterpool);
+ }
+ else
+ {
+ err = (svn_wc_prop_set4(ctx->wc_ctx, target->local_abspath,
+ prop_target->name, prop_val,
+ TRUE, /* ### Skipping checks */
+ NULL, NULL,
+ iterpool));
+ }
+
+ if (err)
+ {
+ /* ### The errors which svn_wc_canonicalize_svn_prop() will
+ * ### return aren't documented. */
+ if (err->apr_err == SVN_ERR_ILLEGAL_TARGET ||
+ err->apr_err == SVN_ERR_NODE_UNEXPECTED_KIND ||
+ err->apr_err == SVN_ERR_IO_UNKNOWN_EOL ||
+ err->apr_err == SVN_ERR_BAD_MIME_TYPE ||
+ err->apr_err == SVN_ERR_CLIENT_INVALID_EXTERNALS_DESCRIPTION)
+ {
+ int i;
+
+ svn_error_clear(err);
+
+ for (i = 0; i < prop_target->content_info->hunks->nelts; i++)
+ {
+ hunk_info_t *hunk_info;
+
+ hunk_info = APR_ARRAY_IDX(prop_target->content_info->hunks,
+ i, hunk_info_t *);
+ hunk_info->rejected = TRUE;
+ SVN_ERR(reject_hunk(target, prop_target->content_info,
+ hunk_info->hunk, prop_target->name,
+ iterpool));
+ }
+ }
+ else
+ return svn_error_return(err);
+ }
+
}
svn_pool_destroy(iterpool);
@@ -2568,9 +2599,6 @@ typedef struct {
/* Number of leading components to strip from patch target paths. */
int strip_count;
- /* Whether to use the old path from the patch file instead of the new one. */
- svn_boolean_t old_patch_target_names;
-
/* Whether to apply the patch in reverse. */
svn_boolean_t reverse;
@@ -2636,7 +2664,6 @@ apply_patches(void *baton,
SVN_ERR(apply_one_patch(&target, patch, btn->abs_wc_path,
btn->ctx->wc_ctx, btn->strip_count,
- btn->old_patch_target_names,
btn->ignore_whitespace,
btn->remove_tempfiles,
btn->patch_func, btn->patch_baton,
@@ -2656,7 +2683,9 @@ apply_patches(void *baton,
if (! target->skipped)
{
- if (target->has_text_changes || target->added)
+ if (target->has_text_changes
+ || target->added
+ || target->deleted)
SVN_ERR(install_patched_target(target, btn->abs_wc_path,
btn->ctx, btn->dry_run,
iterpool));
@@ -2692,7 +2721,6 @@ svn_client_patch(const char *patch_abspa
const char *local_abspath,
svn_boolean_t dry_run,
int strip_count,
- svn_boolean_t old_patch_target_names,
svn_boolean_t reverse,
svn_boolean_t ignore_whitespace,
svn_boolean_t remove_tempfiles,
@@ -2713,7 +2741,6 @@ svn_client_patch(const char *patch_abspa
baton.dry_run = dry_run;
baton.ctx = ctx;
baton.strip_count = strip_count;
- baton.old_patch_target_names = old_patch_target_names;
baton.reverse = reverse;
baton.ignore_whitespace = ignore_whitespace;
baton.remove_tempfiles = remove_tempfiles;
Modified: subversion/branches/py-tests-as-modules/subversion/libsvn_client/prop_commands.c
URL: http://svn.apache.org/viewvc/subversion/branches/py-tests-as-modules/subversion/libsvn_client/prop_commands.c?rev=1031230&r1=1031229&r2=1031230&view=diff
==============================================================================
--- subversion/branches/py-tests-as-modules/subversion/libsvn_client/prop_commands.c (original)
+++ subversion/branches/py-tests-as-modules/subversion/libsvn_client/prop_commands.c Thu Nov 4 20:48:21 2010
@@ -450,6 +450,53 @@ svn_client_propset4(const char *propname
}
}
+static svn_error_t *
+check_and_set_revprop(svn_revnum_t *set_rev,
+ svn_ra_session_t *ra_session,
+ const char *propname,
+ const svn_string_t *original_propval,
+ const svn_string_t *propval,
+ apr_pool_t *pool)
+{
+ if (original_propval)
+ {
+ /* Ensure old value hasn't changed behind our back. */
+ svn_string_t *current;
+ SVN_ERR(svn_ra_rev_prop(ra_session, *set_rev, propname, ¤t, pool));
+
+ if (original_propval->data && (! current))
+ {
+ return svn_error_createf(
+ SVN_ERR_RA_OUT_OF_DATE, NULL,
+ _("revprop '%s' in r%ld is unexpectedly absent "
+ "in repository (maybe someone else deleted it?)"),
+ propname, *set_rev);
+ }
+ else if (original_propval->data
+ && (! svn_string_compare(original_propval, current)))
+ {
+ return svn_error_createf(
+ SVN_ERR_RA_OUT_OF_DATE, NULL,
+ _("revprop '%s' in r%ld has unexpected value "
+ "in repository (maybe someone else changed it?)"),
+ propname, *set_rev);
+ }
+ else if ((! original_propval->data) && current)
+ {
+ return svn_error_createf(
+ SVN_ERR_RA_OUT_OF_DATE, NULL,
+ _("revprop '%s' in r%ld is unexpectedly present "
+ "in repository (maybe someone else set it?)"),
+ propname, *set_rev);
+ }
+ }
+
+ SVN_ERR(svn_ra_change_rev_prop2(ra_session, *set_rev, propname,
+ NULL, propval, pool));
+
+ return SVN_NO_ERROR;
+}
+
svn_error_t *
svn_client_revprop_set2(const char *propname,
const svn_string_t *propval,
@@ -462,6 +509,7 @@ svn_client_revprop_set2(const char *prop
apr_pool_t *pool)
{
svn_ra_session_t *ra_session;
+ svn_boolean_t be_atomic;
if ((strcmp(propname, SVN_PROP_REVISION_AUTHOR) == 0)
&& propval
@@ -485,42 +533,31 @@ svn_client_revprop_set2(const char *prop
SVN_ERR(svn_client__get_revision_number(set_rev, NULL, ctx->wc_ctx, NULL,
ra_session, revision, pool));
- if (original_propval)
- {
- /* Ensure old value hasn't changed behind our back. */
- svn_string_t *current;
- SVN_ERR(svn_ra_rev_prop(ra_session, *set_rev, propname, ¤t, pool));
+ SVN_ERR(svn_ra_has_capability(ra_session, &be_atomic,
+ SVN_RA_CAPABILITY_ATOMIC_REVPROPS, pool));
+ if (be_atomic)
+ {
+ /* Convert ORIGINAL_PROPVAL to an OLD_VALUE_P. */
+ const svn_string_t *const *old_value_p;
+ const svn_string_t *unset = NULL;
+
+ if (original_propval == NULL)
+ old_value_p = NULL;
+ else if (original_propval->data == NULL)
+ old_value_p = &unset;
+ else
+ old_value_p = &original_propval;
- if (original_propval->data && (! current))
- {
- return svn_error_createf(
- SVN_ERR_RA_OUT_OF_DATE, NULL,
- _("revprop '%s' in r%ld is unexpectedly absent "
- "in repository (maybe someone else deleted it?)"),
- propname, *set_rev);
- }
- else if (original_propval->data
- && (! svn_string_compare(original_propval, current)))
- {
- return svn_error_createf(
- SVN_ERR_RA_OUT_OF_DATE, NULL,
- _("revprop '%s' in r%ld has unexpected value "
- "in repository (maybe someone else changed it?)"),
- propname, *set_rev);
- }
- else if ((! original_propval->data) && current)
- {
- return svn_error_createf(
- SVN_ERR_RA_OUT_OF_DATE, NULL,
- _("revprop '%s' in r%ld is unexpectedly present "
- "in repository (maybe someone else set it?)"),
- propname, *set_rev);
- }
+ /* The actual RA call. */
+ SVN_ERR(svn_ra_change_rev_prop2(ra_session, *set_rev, propname,
+ old_value_p, propval, pool));
+ }
+ else
+ {
+ /* The actual RA call. */
+ SVN_ERR(check_and_set_revprop(set_rev, ra_session, propname,
+ original_propval, propval, pool));
}
-
- /* The actual RA call. */
- SVN_ERR(svn_ra_change_rev_prop(ra_session, *set_rev, propname, propval,
- pool));
if (ctx->notify_func2)
{