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 2012/10/21 04:00:47 UTC
svn commit: r1400556 [8/29] - in /subversion/branches/ev2-export: ./ build/
build/ac-macros/ build/generator/ build/generator/templates/ build/hudson/
contrib/client-side/emacs/ contrib/client-side/svn-push/
contrib/client-side/svnmerge/ contrib/hook-s...
Modified: subversion/branches/ev2-export/subversion/libsvn_client/externals.c
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/libsvn_client/externals.c?rev=1400556&r1=1400555&r2=1400556&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/libsvn_client/externals.c (original)
+++ subversion/branches/ev2-export/subversion/libsvn_client/externals.c Sun Oct 21 02:00:31 2012
@@ -59,11 +59,16 @@ relegate_dir_external(svn_wc_context_t *
const char *local_abspath,
svn_cancel_func_t cancel_func,
void *cancel_baton,
+ svn_wc_notify_func2_t notify_func,
+ void *notify_baton,
apr_pool_t *scratch_pool)
{
svn_error_t *err = SVN_NO_ERROR;
- err = svn_wc__external_remove(wc_ctx, wri_abspath, local_abspath,
+ SVN_ERR(svn_wc__acquire_write_lock(NULL, wc_ctx, local_abspath,
+ FALSE, scratch_pool, scratch_pool));
+
+ err = svn_wc__external_remove(wc_ctx, wri_abspath, local_abspath, FALSE,
cancel_func, cancel_baton, scratch_pool);
if (err && (err->apr_err == SVN_ERR_WC_LEFT_LOCAL_MOD))
{
@@ -103,8 +108,33 @@ relegate_dir_external(svn_wc_context_t *
/* Do our best, but no biggy if it fails. The rename will fail. */
svn_error_clear(svn_io_remove_file2(new_path, TRUE, scratch_pool));
- /* Rename. */
- SVN_ERR(svn_io_file_rename(local_abspath, new_path, scratch_pool));
+ /* Rename. If this is still a working copy we should use the working
+ copy rename function (to release open handles) */
+ err = svn_wc__rename_wc(wc_ctx, local_abspath, new_path,
+ scratch_pool);
+
+ if (err && err->apr_err == SVN_ERR_WC_PATH_UNEXPECTED_STATUS)
+ {
+ svn_error_clear(err);
+
+ /* And if it is no longer a working copy, we should just rename
+ it */
+ err = svn_io_file_rename(local_abspath, new_path, scratch_pool);
+ }
+
+ /* ### TODO: We should notify the user about the rename */
+ if (notify_func)
+ {
+ svn_wc_notify_t *notify;
+
+ notify = svn_wc_create_notify(err ? local_abspath : new_path,
+ svn_wc_notify_left_local_modifications,
+ scratch_pool);
+ notify->kind = svn_node_dir;
+ notify->err = err;
+
+ notify_func(notify_baton, notify, scratch_pool);
+ }
}
return svn_error_trace(err);
@@ -174,31 +204,45 @@ switch_dir_external(const char *local_ab
goto cleanup;
}
+ /* We'd really prefer not to have to do a brute-force
+ relegation -- blowing away the current external working
+ copy and checking it out anew -- so we'll first see if we
+ can get away with a generally cheaper relocation (if
+ required) and switch-style update.
+
+ To do so, we need to know the repository root URL of the
+ external working copy as it currently sits. */
SVN_ERR(svn_wc__node_get_repos_info(&repos_root_url, &repos_uuid,
ctx->wc_ctx, local_abspath,
pool, subpool));
if (repos_root_url)
{
- /* URLs don't match. Try to relocate (if necessary) and then
- switch. */
+ /* If the new external target URL is not obviously a
+ child of the external working copy's current
+ repository root URL... */
if (! svn_uri__is_ancestor(repos_root_url, url))
{
const char *repos_root;
svn_ra_session_t *ra_session;
- /* Get the repos root of the new URL. */
- SVN_ERR(svn_client__open_ra_session_internal
- (&ra_session, NULL, url, NULL, NULL,
- FALSE, TRUE, ctx, subpool));
+ /* ... then figure out precisely which repository
+ root URL that target URL *is* a child of ... */
+ SVN_ERR(svn_client__open_ra_session_internal(&ra_session,
+ NULL, url, NULL,
+ NULL, FALSE,
+ TRUE, ctx,
+ subpool));
SVN_ERR(svn_ra_get_repos_root2(ra_session, &repos_root,
subpool));
+ /* ... and use that to try to relocate the external
+ working copy to the target location. */
err = svn_client_relocate2(local_abspath, 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. */
+ repos_root, FALSE, ctx, subpool);
+
+ /* If the relocation failed because the new URL
+ points to a totally different repository, we've
+ no choice but to relegate and check out a new WC. */
if (err
&& (err->apr_err == SVN_ERR_WC_INVALID_RELOCATION
|| (err->apr_err
@@ -209,6 +253,10 @@ switch_dir_external(const char *local_ab
}
else if (err)
return svn_error_trace(err);
+
+ /* If the relocation went without a hitch, we should
+ have a new repository root URL. */
+ repos_root_url = repos_root;
}
SVN_ERR(svn_client__switch_internal(NULL, local_abspath, url,
@@ -247,12 +295,10 @@ switch_dir_external(const char *local_ab
if (kind == svn_node_dir)
{
/* Buh-bye, old and busted ... */
- SVN_ERR(svn_wc__acquire_write_lock(NULL, ctx->wc_ctx, local_abspath,
- FALSE, pool, pool));
-
SVN_ERR(relegate_dir_external(ctx->wc_ctx, defining_abspath,
local_abspath,
ctx->cancel_func, ctx->cancel_baton,
+ ctx->notify_func2, ctx->notify_baton2,
pool));
}
else
@@ -429,14 +475,19 @@ switch_file_external(const char *local_a
### We can't enable this now, because that would move the external
### information into the wrong working copy */
const char *definition_abspath = svn_dirent_dirname(local_abspath,subpool);
+ apr_array_header_t *inherited_props;
/* Open an RA session to 'source' URL */
SVN_ERR(svn_client__ra_session_from_path2(&ra_session, &switch_loc,
url, dir_abspath,
peg_revision, revision,
ctx, subpool));
+ /* Get the external file's iprops. */
+ SVN_ERR(svn_ra_get_inherited_props(ra_session, &inherited_props, "",
+ switch_loc->rev, subpool, subpool));
- SVN_ERR(svn_ra_reparent(ra_session, url, subpool));
+ SVN_ERR(svn_ra_reparent(ra_session, svn_uri_dirname(url, subpool),
+ subpool));
SVN_ERR(svn_wc__get_file_external_editor(&switch_editor, &switch_baton,
&revnum, ctx->wc_ctx,
@@ -445,6 +496,7 @@ switch_file_external(const char *local_a
switch_loc->url,
switch_loc->repos_root_url,
switch_loc->repos_uuid,
+ inherited_props,
use_commit_times,
diff3_cmd, preserved_exts,
definition_abspath /* def */,
@@ -512,19 +564,18 @@ handle_external_item_removal(const svn_c
SVN_ERR(svn_wc_read_kind(&kind, ctx->wc_ctx, local_abspath, FALSE,
scratch_pool));
- if (kind == svn_node_none)
- return SVN_NO_ERROR; /* It's neither... Nothing to remove */
-
- SVN_ERR(svn_wc_locked2(&lock_existed, NULL, ctx->wc_ctx,
- local_abspath, scratch_pool));
-
- if (! lock_existed)
+ if (kind != svn_node_none)
{
- SVN_ERR(svn_wc__acquire_write_lock(&lock_root_abspath,
- ctx->wc_ctx, local_abspath,
- FALSE,
- scratch_pool,
- scratch_pool));
+ SVN_ERR(svn_wc_locked2(&lock_existed, NULL, ctx->wc_ctx,
+ local_abspath, scratch_pool));
+
+ if (! lock_existed)
+ {
+ SVN_ERR(svn_wc__acquire_write_lock(&lock_root_abspath,
+ ctx->wc_ctx, local_abspath,
+ FALSE,
+ scratch_pool, scratch_pool));
+ }
}
/* We don't use relegate_dir_external() here, because we know that
@@ -532,7 +583,7 @@ handle_external_item_removal(const svn_c
going to need this directory, and therefore it's better to
leave stuff where the user expects it. */
err = svn_wc__external_remove(ctx->wc_ctx, defining_abspath,
- local_abspath,
+ local_abspath, (kind == svn_node_none),
ctx->cancel_func, ctx->cancel_baton,
scratch_pool);
@@ -547,6 +598,17 @@ handle_external_item_removal(const svn_c
notify->err = err;
(ctx->notify_func2)(ctx->notify_baton2, notify, scratch_pool);
+
+ if (err && err->apr_err == SVN_ERR_WC_LEFT_LOCAL_MOD)
+ {
+ notify = svn_wc_create_notify(local_abspath,
+ svn_wc_notify_left_local_modifications,
+ scratch_pool);
+ notify->kind = svn_node_dir;
+ notify->err = err;
+
+ (ctx->notify_func2)(ctx->notify_baton2, notify, scratch_pool);
+ }
}
if (err && err->apr_err == SVN_ERR_WC_LEFT_LOCAL_MOD)
@@ -791,6 +853,7 @@ handle_externals_change(svn_client_ctx_t
const char *old_defining_abspath;
svn_wc_external_item2_t *new_item;
const char *target_abspath;
+ svn_boolean_t under_root;
new_item = APR_ARRAY_IDX(new_desc, i, svn_wc_external_item2_t *);
@@ -799,8 +862,20 @@ handle_externals_change(svn_client_ctx_t
if (ctx->cancel_func)
SVN_ERR(ctx->cancel_func(ctx->cancel_baton));
- target_abspath = svn_dirent_join(local_abspath, new_item->target_dir,
- iterpool);
+ SVN_ERR(svn_dirent_is_under_root(&under_root, &target_abspath,
+ local_abspath, new_item->target_dir,
+ iterpool));
+
+ if (! under_root)
+ {
+ return svn_error_createf(
+ SVN_ERR_WC_OBSTRUCTED_UPDATE, NULL,
+ _("Path '%s' is not in the working copy"),
+ svn_dirent_local_style(
+ svn_dirent_join(local_abspath, new_item->target_dir,
+ iterpool),
+ iterpool));
+ }
old_defining_abspath = apr_hash_get(old_externals, target_abspath,
APR_HASH_KEY_STRING);
@@ -984,13 +1059,26 @@ svn_client__export_externals(apr_hash_t
{
const char *item_abspath;
const char *new_url;
+ svn_boolean_t under_root;
svn_wc_external_item2_t *item = APR_ARRAY_IDX(items, i,
svn_wc_external_item2_t *);
svn_pool_clear(sub_iterpool);
- item_abspath = svn_dirent_join(local_abspath, item->target_dir,
- sub_iterpool);
+ SVN_ERR(svn_dirent_is_under_root(&under_root, &item_abspath,
+ local_abspath, item->target_dir,
+ sub_iterpool));
+
+ if (! under_root)
+ {
+ return svn_error_createf(
+ SVN_ERR_WC_OBSTRUCTED_UPDATE, NULL,
+ _("Path '%s' is not in the working copy"),
+ svn_dirent_local_style(
+ svn_dirent_join(local_abspath, item->target_dir,
+ sub_iterpool),
+ sub_iterpool));
+ }
SVN_ERR(svn_wc__resolve_relative_external_url(&new_url, item,
repos_root_url,
@@ -1092,35 +1180,3 @@ svn_client__do_external_status(svn_clien
return SVN_NO_ERROR;
}
-
-/* Implements the `svn_wc_externals_update_t' interface. */
-svn_error_t *
-svn_client__external_info_gatherer(void *baton,
- const char *local_abspath,
- const svn_string_t *old_value,
- const svn_string_t *new_value,
- svn_depth_t depth,
- apr_pool_t *scratch_pool)
-{
- svn_client__external_func_baton_t *efb = baton;
-
- local_abspath = apr_pstrdup(efb->result_pool, local_abspath);
-
- if (efb->externals_old != NULL && old_value != NULL)
- apr_hash_set(efb->externals_old, local_abspath, APR_HASH_KEY_STRING,
- apr_pstrndup(efb->result_pool,
- old_value->data, old_value->len));
-
- if (efb->externals_new != NULL && new_value != NULL)
- apr_hash_set(efb->externals_new, local_abspath, APR_HASH_KEY_STRING,
- apr_pstrndup(efb->result_pool,
- new_value->data, new_value->len));
-
- if (efb->ambient_depths != NULL)
- apr_hash_set(efb->ambient_depths, local_abspath, APR_HASH_KEY_STRING,
- svn_depth_to_word(depth));
-
- return SVN_NO_ERROR;
-}
-
-
Modified: subversion/branches/ev2-export/subversion/libsvn_client/merge.c
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/libsvn_client/merge.c?rev=1400556&r1=1400555&r2=1400556&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/libsvn_client/merge.c (original)
+++ subversion/branches/ev2-export/subversion/libsvn_client/merge.c Sun Oct 21 02:00:31 2012
@@ -27,6 +27,7 @@
/*** Includes ***/
+#include <assert.h>
#include <apr_strings.h>
#include <apr_tables.h>
#include <apr_hash.h>
@@ -273,7 +274,7 @@ typedef struct merge_cmd_baton_t {
See http://subversion.tigris.org/issues/show_bug.cgi?id=3432.
Updated during each call to do_directory_merge(). May be NULL if there
is no gap. */
- apr_array_header_t *implicit_src_gap;
+ svn_rangelist_t *implicit_src_gap;
svn_client_ctx_t *ctx; /* Client context for callbacks, etc. */
@@ -363,6 +364,21 @@ typedef struct merge_cmd_baton_t {
/*** Utilities ***/
+/* Return TRUE iff the session URL of RA_SESSION is equal to URL. Useful in
+ * asserting preconditions. */
+static svn_boolean_t
+session_url_is(svn_ra_session_t *ra_session,
+ const char *url,
+ apr_pool_t *scratch_pool)
+{
+ const char *session_url;
+ svn_error_t *err
+ = svn_ra_get_session_url(ra_session, &session_url, scratch_pool);
+
+ SVN_ERR_ASSERT_NO_RETURN(! err);
+ return strcmp(url, session_url) == 0;
+}
+
/* Return a new merge_source_t structure, allocated in RESULT_POOL,
* initialized with deep copies of LOC1 and LOC2 and ANCESTRAL. */
static merge_source_t *
@@ -807,7 +823,7 @@ split_mergeinfo_on_revision(svn_mergeinf
{
int i;
const char *merge_source_path = svn__apr_hash_index_key(hi);
- apr_array_header_t *rangelist = svn__apr_hash_index_val(hi);
+ svn_rangelist_t *rangelist = svn__apr_hash_index_val(hi);
svn_pool_clear(iterpool);
@@ -829,7 +845,7 @@ split_mergeinfo_on_revision(svn_mergeinf
than REVISION. Remove the younger rangelists from
*MERGEINFO and put them in *YOUNGER_MERGEINFO. */
int j;
- apr_array_header_t *younger_rangelist =
+ svn_rangelist_t *younger_rangelist =
apr_array_make(pool, 1, sizeof(svn_merge_range_t *));
for (j = i; j < rangelist->nelts; j++)
@@ -1032,9 +1048,9 @@ filter_self_referential_mergeinfo(apr_ar
{
int j;
const char *source_path = svn__apr_hash_index_key(hi);
- apr_array_header_t *rangelist = svn__apr_hash_index_val(hi);
+ svn_rangelist_t *rangelist = svn__apr_hash_index_val(hi);
const char *merge_source_url;
- apr_array_header_t *adjusted_rangelist =
+ svn_rangelist_t *adjusted_rangelist =
apr_array_make(iterpool, 0, sizeof(svn_merge_range_t *));
merge_source_url =
@@ -1591,8 +1607,8 @@ merge_file_changed(svn_wc_notify_state_t
way svn_wc_merge5() can do the merge. */
if (wc_kind != svn_node_file || is_deleted)
{
- const char *moved_to_abspath;
- svn_error_t *err;
+ svn_boolean_t moved_away;
+ svn_wc_conflict_reason_t reason;
/* Maybe the node is excluded via depth filtering? */
@@ -1622,44 +1638,23 @@ merge_file_changed(svn_wc_notify_state_t
/* This is use case 4 described in the paper attached to issue
* #2282. See also notes/tree-conflicts/detection.txt
*/
- err = svn_wc__node_was_moved_away(&moved_to_abspath, NULL,
- ctx->wc_ctx, local_abspath,
- scratch_pool, scratch_pool);
- if (err)
- {
- if (err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND)
- {
- svn_error_clear(err);
- moved_to_abspath = NULL;
- }
- else
- return svn_error_trace(err);
- }
-
- if (moved_to_abspath)
- {
- /* File has been moved away locally -- apply incoming
- * changes at the new location. */
- local_abspath = moved_to_abspath;
- }
+ SVN_ERR(check_moved_away(&moved_away, ctx->wc_ctx,
+ local_abspath, scratch_pool));
+ if (moved_away)
+ reason = svn_wc_conflict_reason_moved_away;
+ else if (is_deleted)
+ reason = svn_wc_conflict_reason_deleted;
else
- {
- svn_wc_conflict_reason_t reason;
-
- if (is_deleted)
- reason = svn_wc_conflict_reason_deleted;
- else
- reason = svn_wc_conflict_reason_missing;
- SVN_ERR(tree_conflict(merge_b, local_abspath, svn_node_file,
- svn_wc_conflict_action_edit, reason));
- if (tree_conflicted)
- *tree_conflicted = TRUE;
- if (content_state)
- *content_state = svn_wc_notify_state_missing;
- if (prop_state)
- *prop_state = svn_wc_notify_state_missing;
- return SVN_NO_ERROR;
- }
+ reason = svn_wc_conflict_reason_missing;
+ SVN_ERR(tree_conflict(merge_b, local_abspath, svn_node_file,
+ svn_wc_conflict_action_edit, reason));
+ if (tree_conflicted)
+ *tree_conflicted = TRUE;
+ if (content_state)
+ *content_state = svn_wc_notify_state_missing;
+ if (prop_state)
+ *prop_state = svn_wc_notify_state_missing;
+ return SVN_NO_ERROR;
}
/* ### TODO: Thwart attempts to merge into a path that has
@@ -1888,7 +1883,7 @@ merge_file_added(svn_wc_notify_state_t *
svn_revnum_t copyfrom_rev;
svn_stream_t *new_contents, *new_base_contents;
apr_hash_t *new_base_props, *new_props;
- const svn_wc_conflict_description2_t *existing_conflict;
+ svn_boolean_t existing_tree_conflict;
svn_error_t *err;
/* If this is a merge from the same repository as our
@@ -1925,10 +1920,9 @@ merge_file_added(svn_wc_notify_state_t *
scratch_pool, scratch_pool));
}
- err = svn_wc__get_tree_conflict(&existing_conflict,
- merge_b->ctx->wc_ctx,
- mine_abspath, merge_b->pool,
- merge_b->pool);
+ err = svn_wc_conflicted_p3(NULL, NULL, &existing_tree_conflict,
+ merge_b->ctx->wc_ctx, mine_abspath,
+ merge_b->pool);
if (err)
{
@@ -1936,10 +1930,10 @@ merge_file_added(svn_wc_notify_state_t *
return svn_error_trace(err);
svn_error_clear(err);
- existing_conflict = FALSE;
+ existing_tree_conflict = FALSE;
}
- if (existing_conflict)
+ if (existing_tree_conflict)
{
svn_boolean_t moved_here;
svn_wc_conflict_reason_t reason;
@@ -2731,7 +2725,7 @@ merge_dir_closed(svn_wc_notify_state_t *
merge_cmd_baton_t *merge_b = baton;
if (merge_b->dry_run)
- svn_hash__clear(merge_b->dry_run_deletions, scratch_pool);
+ SVN_ERR(svn_hash__clear(merge_b->dry_run_deletions, scratch_pool));
return SVN_NO_ERROR;
}
@@ -3194,8 +3188,8 @@ notification_receiver(void *baton, const
* effect is to discard any non-inheritable input ranges. Therefore the
* ranges in *OUT_RANGELIST will always be inheritable. */
static svn_error_t *
-rangelist_intersect_range(apr_array_header_t **out_rangelist,
- const apr_array_header_t *in_rangelist,
+rangelist_intersect_range(svn_rangelist_t **out_rangelist,
+ const svn_rangelist_t *in_rangelist,
svn_revnum_t rev1,
svn_revnum_t rev2,
svn_boolean_t consider_inheritance,
@@ -3206,7 +3200,7 @@ rangelist_intersect_range(apr_array_head
if (rev1 < rev2)
{
- apr_array_header_t *simple_rangelist =
+ svn_rangelist_t *simple_rangelist =
svn_rangelist__initialize(rev1, rev2, TRUE, scratch_pool);
SVN_ERR(svn_rangelist_intersect(out_rangelist,
@@ -3334,7 +3328,7 @@ adjust_deleted_subtree_ranges(svn_client
http://subversion.tigris.org/issues/show_bug.cgi?id=3137 fixed some of
the cases where different RA layers returned different error codes to
signal the "path not found"...but it looks like there is more to do.
-
+
### Do we still need to special case for ra_neon (since it no longer
exists)? */
if (err)
@@ -3366,7 +3360,7 @@ adjust_deleted_subtree_ranges(svn_client
}
else
{
- apr_array_header_t *deleted_rangelist;
+ svn_rangelist_t *deleted_rangelist;
svn_revnum_t rev_primary_url_deleted;
/* PRIMARY_URL@older_rev exists, so it was deleted at some
@@ -3435,7 +3429,7 @@ adjust_deleted_subtree_ranges(svn_client
}
else /* PRIMARY_URL@peg_rev exists. */
{
- apr_array_header_t *non_existent_rangelist;
+ svn_rangelist_t *non_existent_rangelist;
svn_location_segment_t *segment =
APR_ARRAY_IDX(segments, (segments->nelts - 1),
svn_location_segment_t *);
@@ -3503,7 +3497,7 @@ adjust_deleted_subtree_ranges(svn_client
SOURCE is cascaded from the argument of the same name in
do_directory_merge(). TARGET is the merge target. RA_SESSION is the
- session for the younger of SOURCE->url1@rev1 and SOURCE->url2@rev2.
+ session for the younger of SOURCE->loc1 and SOURCE->loc2.
Adjust the subtrees in CHILDREN_WITH_MERGEINFO so that we don't
later try to describe invalid paths in drive_merge_report_editor().
@@ -3526,6 +3520,10 @@ fix_deleted_subtree_ranges(const merge_s
apr_pool_t *iterpool = svn_pool_create(scratch_pool);
svn_boolean_t is_rollback = source->loc2->rev < source->loc1->rev;
+ assert(session_url_is(ra_session,
+ (is_rollback ? source->loc1 : source->loc2)->url,
+ scratch_pool));
+
/* CHILDREN_WITH_MERGEINFO is sorted in depth-first order, so
start at index 1 to examine only subtrees. */
for (i = 1; i < children_with_mergeinfo->nelts; i++)
@@ -3533,7 +3531,7 @@ fix_deleted_subtree_ranges(const merge_s
svn_client__merge_path_t *child =
APR_ARRAY_IDX(children_with_mergeinfo, i, svn_client__merge_path_t *);
svn_client__merge_path_t *parent;
- apr_array_header_t *deleted_rangelist, *added_rangelist;
+ svn_rangelist_t *deleted_rangelist, *added_rangelist;
SVN_ERR_ASSERT(child);
if (child->absent)
@@ -3576,8 +3574,8 @@ fix_deleted_subtree_ranges(const merge_s
described by SOURCE can potentially be merged to CHILD.
But if CHILD is a subtree we don't have the same guarantees about
- SOURCE as we do for the merge target. SOURCE->url1@rev1 and/or
- SOURCE->url2@rev2 might not exist.
+ SOURCE as we do for the merge target. SOURCE->loc1 and/or
+ SOURCE->loc2 might not exist.
If one or both doesn't exist, then adjust CHILD->REMAINING_RANGES
such that we don't later try to describe invalid subtrees in
@@ -3885,7 +3883,7 @@ static svn_error_t *
filter_merged_revisions(svn_client__merge_path_t *parent,
svn_client__merge_path_t *child,
const char *mergeinfo_path,
- apr_array_header_t *target_rangelist,
+ svn_rangelist_t *target_rangelist,
svn_revnum_t revision1,
svn_revnum_t revision2,
svn_boolean_t child_inherits_implicit,
@@ -3894,7 +3892,7 @@ filter_merged_revisions(svn_client__merg
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
- apr_array_header_t *requested_rangelist,
+ svn_rangelist_t *requested_rangelist,
*target_implicit_rangelist, *explicit_rangelist;
/* Convert REVISION1 and REVISION2 to a rangelist.
@@ -3913,7 +3911,7 @@ filter_merged_revisions(svn_client__merg
if (revision1 > revision2) /* This is a reverse merge. */
{
- apr_array_header_t *added_rangelist, *deleted_rangelist;
+ svn_rangelist_t *added_rangelist, *deleted_rangelist;
/* The revert range and will need to be reversed for
our svn_rangelist_* APIs to work properly. */
@@ -3969,7 +3967,7 @@ filter_merged_revisions(svn_client__merg
}
else /* We need to check CHILD's implicit mergeinfo. */
{
- apr_array_header_t *implicit_rangelist;
+ svn_rangelist_t *implicit_rangelist;
SVN_ERR(ensure_implicit_mergeinfo(parent,
child,
@@ -4101,8 +4099,8 @@ filter_merged_revisions(svn_client__merg
ancestor - see 'THE CHILDREN_WITH_MERGEINFO ARRAY'. TARGET_MERGEINFO is
the working mergeinfo on CHILD.
- RA_SESSION is the session for the younger of SOURCE->url1@rev1 and
- SOURCE->url2@rev2.
+ RA_SESSION is the session for the younger of SOURCE->loc1 and
+ SOURCE->loc2.
If the function needs to consider CHILD->IMPLICIT_MERGEINFO and
CHILD_INHERITS_IMPLICIT is true, then set CHILD->IMPLICIT_MERGEINFO to the
@@ -4146,7 +4144,7 @@ calculate_remaining_ranges(svn_client__m
scratch_pool);
/* Intersection of TARGET_MERGEINFO and the merge history
described by SOURCE. */
- apr_array_header_t *target_rangelist;
+ svn_rangelist_t *target_rangelist;
svn_revnum_t child_base_revision;
/* Since this function should only be called when honoring mergeinfo and
@@ -4302,7 +4300,7 @@ find_gaps_in_merge_source_history(svn_re
= (source->loc1->rev < source->loc2->rev) ? source->loc2 : source->loc1;
const char *merge_src_fspath = svn_client__pathrev_fspath(primary_src,
scratch_pool);
- apr_array_header_t *rangelist;
+ svn_rangelist_t *rangelist;
SVN_ERR_ASSERT(source->ancestral);
@@ -4357,13 +4355,13 @@ find_gaps_in_merge_source_history(svn_re
}
else if (apr_hash_count(implicit_src_mergeinfo) > 1) /* Rename */
{
- apr_array_header_t *requested_rangelist =
+ svn_rangelist_t *requested_rangelist =
svn_rangelist__initialize(MIN(source->loc1->rev, source->loc2->rev),
MAX(source->loc1->rev, source->loc2->rev),
TRUE, scratch_pool);
- apr_array_header_t *implicit_rangelist =
+ svn_rangelist_t *implicit_rangelist =
apr_array_make(scratch_pool, 2, sizeof(svn_merge_range_t *));
- apr_array_header_t *gap_rangelist;
+ svn_rangelist_t *gap_rangelist;
SVN_ERR(svn_rangelist__merge_many(implicit_rangelist,
implicit_src_mergeinfo,
@@ -4490,13 +4488,13 @@ populate_remaining_ranges(apr_array_head
return SVN_NO_ERROR;
}
- /* If, in the merge source's history, there was a copy from a older
- revision, then SOURCE->url2 won't exist at some range M:N, where
- source->rev1 < M < N < source->rev2. The rules of 'MERGEINFO MERGE
- SOURCE NORMALIZATION' allow this, but we must ignore these gaps when
- calculating what ranges remain to be merged from SOURCE. If we don't
- and try to merge any part of SOURCE->url2@M:N we would break the
- editor since no part of that actually exists. See
+ /* If, in the merge source's history, there was a copy from an older
+ revision, then SOURCE->loc2->url won't exist at some range M:N, where
+ SOURCE->loc1->rev < M < N < SOURCE->loc2->rev. The rules of 'MERGEINFO
+ MERGE SOURCE NORMALIZATION' allow this, but we must ignore these gaps
+ when calculating what ranges remain to be merged from SOURCE. If we
+ don't and try to merge any part of SOURCE->loc2->url@M:N we would
+ break the editor since no part of that actually exists. See
http://svn.haxx.se/dev/archive-2008-11/0618.shtml.
Find the gaps in the merge target's history, if any. Eventually
@@ -4693,8 +4691,8 @@ update_wc_mergeinfo(svn_mergeinfo_catalo
for (hi = apr_hash_first(scratch_pool, merges); hi; hi = apr_hash_next(hi))
{
const char *local_abspath = svn__apr_hash_index_key(hi);
- apr_array_header_t *ranges = svn__apr_hash_index_val(hi);
- apr_array_header_t *rangelist;
+ svn_rangelist_t *ranges = svn__apr_hash_index_val(hi);
+ svn_rangelist_t *rangelist;
svn_error_t *err;
const char *local_abspath_rel_to_target;
const char *fspath;
@@ -4826,7 +4824,7 @@ update_wc_mergeinfo(svn_mergeinfo_catalo
MERGEINFO_PATH to MERGE_B->target. */
static svn_error_t *
record_skips(const char *mergeinfo_path,
- const apr_array_header_t *rangelist,
+ const svn_rangelist_t *rangelist,
svn_boolean_t is_rollback,
apr_hash_t *skipped_abspaths,
merge_cmd_baton_t *merge_b,
@@ -5030,8 +5028,8 @@ remove_children_with_deleted_mergeinfo(m
URL in the repository of SOURCE; they may be temporarily reparented within
this function.
- If SOURCE->ancestral is set, then SOURCE->url1@rev1 must be a
- historical ancestor of SOURCE->url2@rev2, or vice-versa (see
+ If SOURCE->ancestral is set, then SOURCE->loc1 must be a
+ historical ancestor of SOURCE->loc2, or vice-versa (see
`MERGEINFO MERGE SOURCE NORMALIZATION' for more requirements around
SOURCE in this case).
*/
@@ -5110,7 +5108,7 @@ drive_merge_report_editor(const char *ta
SVN_ERR(svn_client__ensure_ra_session_url(&old_sess1_url,
merge_b->ra_session1,
source->loc1->url, scratch_pool));
- /* Temporarily point our second RA session to SOURCE->url1, too. We use
+ /* Temporarily point our second RA session to SOURCE->loc1->url, too. We use
this to request individual file contents. */
SVN_ERR(svn_client__ensure_ra_session_url(&old_sess2_url,
merge_b->ra_session2,
@@ -5401,6 +5399,7 @@ single_file_merge_get_file(const char **
{
svn_stream_t *stream;
const char *old_sess_url;
+ svn_error_t *err;
SVN_ERR(svn_stream_open_unique(&stream, filename,
svn_dirent_dirname(wc_target, pool),
@@ -5408,9 +5407,10 @@ single_file_merge_get_file(const char **
SVN_ERR(svn_client__ensure_ra_session_url(&old_sess_url, ra_session, location->url,
pool));
- SVN_ERR(svn_ra_get_file(ra_session, "", location->rev,
- stream, NULL, props, pool));
- SVN_ERR(svn_ra_reparent(ra_session, old_sess_url, pool));
+ err = svn_ra_get_file(ra_session, "", location->rev,
+ stream, NULL, props, pool);
+ SVN_ERR(svn_error_compose_create(
+ err, svn_ra_reparent(ra_session, old_sess_url, pool)));
return svn_stream_close(stream);
}
@@ -5732,10 +5732,10 @@ get_wc_explicit_mergeinfo_catalog(apr_ha
apr_pool_t *iterpool = svn_pool_create(scratch_pool);
apr_hash_index_t *hi;
- SVN_ERR(svn_client_propget4(subtrees_with_mergeinfo, SVN_PROP_MERGEINFO,
- target_abspath, &working_revision,
- &working_revision, NULL, depth, NULL,
- ctx, result_pool, scratch_pool));
+ SVN_ERR(svn_client_propget5(subtrees_with_mergeinfo, NULL,
+ SVN_PROP_MERGEINFO, target_abspath,
+ &working_revision, &working_revision, NULL,
+ depth, NULL, ctx, result_pool, scratch_pool));
/* Convert property values to svn_mergeinfo_t. */
for (hi = apr_hash_first(scratch_pool, *subtrees_with_mergeinfo);
@@ -6239,7 +6239,7 @@ log_changed_revs(void *baton,
static void
merge_range_find_extremes(svn_revnum_t *min_rev_p,
svn_revnum_t *max_rev_p,
- const apr_array_header_t *rangelist)
+ const svn_rangelist_t *rangelist)
{
int i;
@@ -6258,15 +6258,16 @@ merge_range_find_extremes(svn_revnum_t *
*max_rev_p = range_max;
}
}
+
/* Wrapper around svn_ra_get_log2(). Invoke RECEIVER with RECEIVER_BATON
- * on each commit from START to END on TARGET.
- * Important: Revision properties are not retrieved by this functions for
+ * on each commit from YOUNGEST_REV to OLDEST_REV in which TARGET_RELPATH
+ * changed. TARGET_RELPATH is relative to RA_SESSION's URL.
+ * Important: Revision properties are not retrieved by this function for
* performance reasons.
*/
-
static svn_error_t *
get_log(svn_ra_session_t *ra_session,
- const char *target,
+ const char *target_relpath,
svn_revnum_t youngest_rev,
svn_revnum_t oldest_rev,
svn_boolean_t discover_changed_paths,
@@ -6276,14 +6277,16 @@ get_log(svn_ra_session_t *ra_session,
{
apr_array_header_t *log_targets;
apr_array_header_t *revprops;
-
+
log_targets = apr_array_make(pool, 1, sizeof(const char *));
- APR_ARRAY_PUSH(log_targets, const char *) = target;
+ APR_ARRAY_PUSH(log_targets, const char *) = target_relpath;
revprops = apr_array_make(pool, 0, sizeof(const char *));
SVN_ERR(svn_ra_get_log2(ra_session, log_targets, youngest_rev,
- oldest_rev, 0, discover_changed_paths, FALSE, FALSE,
+ oldest_rev, 0 /* limit */, discover_changed_paths,
+ FALSE /* strict_node_history */,
+ FALSE /* include_merged_revisions */,
revprops, receiver, receiver_baton, pool));
return SVN_NO_ERROR;
@@ -6302,16 +6305,16 @@ get_log(svn_ra_session_t *ra_session,
Use POOL for temporary allocations. */
static svn_error_t *
-remove_noop_merge_ranges(apr_array_header_t **operative_ranges_p,
+remove_noop_merge_ranges(svn_rangelist_t **operative_ranges_p,
svn_ra_session_t *ra_session,
- const apr_array_header_t *ranges,
+ const svn_rangelist_t *ranges,
apr_pool_t *pool)
{
int i;
svn_revnum_t oldest_rev, youngest_rev;
apr_array_header_t *changed_revs =
apr_array_make(pool, ranges->nelts, sizeof(svn_revnum_t));
- apr_array_header_t *operative_ranges =
+ svn_rangelist_t *operative_ranges =
apr_array_make(ranges->pool, ranges->nelts, ranges->elt_size);
/* Find the revision extremes of the RANGES we have. */
@@ -6377,7 +6380,7 @@ remove_noop_merge_ranges(apr_array_heade
/*** Merge Source Normalization ***/
/* qsort-compatible sort routine, rating merge_source_t * objects to
- be in descending (youngest-to-oldest) order based on their ->rev1
+ be in descending (youngest-to-oldest) order based on their ->loc1->rev
component. */
static int
compare_merge_source_ts(const void *a,
@@ -6499,7 +6502,7 @@ combine_range_with_segments(apr_array_he
static svn_error_t *
normalize_merge_sources_internal(apr_array_header_t **merge_sources_p,
const svn_client__pathrev_t *source_loc,
- const apr_array_header_t *merge_range_ts,
+ const svn_rangelist_t *merge_range_ts,
svn_ra_session_t *ra_session,
svn_client_ctx_t *ctx,
apr_pool_t *result_pool,
@@ -6676,7 +6679,7 @@ static svn_error_t *
normalize_merge_sources(apr_array_header_t **merge_sources_p,
const char *source_path_or_url,
const svn_client__pathrev_t *source_loc,
- const apr_array_header_t *ranges_to_merge,
+ const svn_rangelist_t *ranges_to_merge,
svn_ra_session_t *ra_session,
svn_client_ctx_t *ctx,
apr_pool_t *result_pool,
@@ -6684,7 +6687,7 @@ normalize_merge_sources(apr_array_header
{
const char *source_abspath_or_url;
svn_revnum_t youngest_rev = SVN_INVALID_REVNUM;
- apr_array_header_t *merge_range_ts;
+ svn_rangelist_t *merge_range_ts;
int i;
apr_pool_t *iterpool = svn_pool_create(scratch_pool);
@@ -6763,14 +6766,14 @@ normalize_merge_sources(apr_array_header
Allocate *FILTERED_RANGELIST in POOL. */
static svn_error_t *
-filter_natural_history_from_mergeinfo(apr_array_header_t **filtered_rangelist,
+filter_natural_history_from_mergeinfo(svn_rangelist_t **filtered_rangelist,
const char *source_rel_path,
svn_mergeinfo_t implicit_mergeinfo,
svn_merge_range_t *requested_range,
apr_pool_t *pool)
{
/* Make the REQUESTED_RANGE into a rangelist. */
- apr_array_header_t *requested_rangelist =
+ svn_rangelist_t *requested_rangelist =
svn_rangelist__initialize(requested_range->start, requested_range->end,
requested_range->inheritable, pool);
@@ -6781,7 +6784,7 @@ filter_natural_history_from_mergeinfo(ap
if (implicit_mergeinfo
&& (requested_range->start < requested_range->end))
{
- apr_array_header_t *implied_rangelist =
+ svn_rangelist_t *implied_rangelist =
apr_hash_get(implicit_mergeinfo, source_rel_path,
APR_HASH_KEY_STRING);
@@ -6855,8 +6858,8 @@ subrange_source(const merge_source_t *so
and the value is the new mergeinfo for that path. Allocate additions
to RESULT_CATALOG in pool which RESULT_CATALOG was created in.
- Note: MERGE_B->RA_SESSION1 must be associated with SOURCE->url1 and
- MERGE_B->RA_SESSION2 with SOURCE->url2.
+ Note: MERGE_B->RA_SESSION1 must be associated with SOURCE->loc1->url and
+ MERGE_B->RA_SESSION2 with SOURCE->loc2->url.
*/
static svn_error_t *
do_file_merge(svn_mergeinfo_catalog_t result_catalog,
@@ -6868,7 +6871,7 @@ do_file_merge(svn_mergeinfo_catalog_t re
merge_cmd_baton_t *merge_b,
apr_pool_t *scratch_pool)
{
- apr_array_header_t *remaining_ranges;
+ svn_rangelist_t *remaining_ranges;
svn_client_ctx_t *ctx = merge_b->ctx;
svn_merge_range_t range;
svn_mergeinfo_t target_mergeinfo;
@@ -6945,7 +6948,7 @@ do_file_merge(svn_mergeinfo_catalog_t re
if (!merge_b->record_only)
{
- apr_array_header_t *ranges_to_merge = remaining_ranges;
+ svn_rangelist_t *ranges_to_merge = remaining_ranges;
const char *target_relpath = ""; /* relative to root of merge */
int i;
@@ -6956,15 +6959,18 @@ do_file_merge(svn_mergeinfo_catalog_t re
if (source->ancestral && (remaining_ranges->nelts > 1))
{
const char *old_sess_url;
+ svn_error_t *err;
+
SVN_ERR(svn_client__ensure_ra_session_url(&old_sess_url,
merge_b->ra_session1,
primary_src->url,
iterpool));
- SVN_ERR(remove_noop_merge_ranges(&ranges_to_merge,
- merge_b->ra_session1,
- remaining_ranges, scratch_pool));
- SVN_ERR(svn_ra_reparent(merge_b->ra_session1, old_sess_url,
- iterpool));
+ err = remove_noop_merge_ranges(&ranges_to_merge,
+ merge_b->ra_session1,
+ remaining_ranges, scratch_pool);
+ SVN_ERR(svn_error_compose_create(
+ err, svn_ra_reparent(merge_b->ra_session1, old_sess_url,
+ iterpool)));
}
for (i = 0; i < ranges_to_merge->nelts; i++)
@@ -7068,11 +7074,10 @@ do_file_merge(svn_mergeinfo_catalog_t re
r, &header_sent, iterpool);
}
- /* Ignore if temporary file not found. It may have been renamed. */
- /* (This is where we complain about missing Lisp, or better yet,
- Python...) */
- SVN_ERR(svn_io_remove_file2(tmpfile1, TRUE, iterpool));
- SVN_ERR(svn_io_remove_file2(tmpfile2, TRUE, iterpool));
+ /* Remove the temporary files. Ignore if not found: they may
+ * have been renamed. */
+ SVN_ERR(svn_io_remove_file2(tmpfile1, TRUE /*ignore*/, iterpool));
+ SVN_ERR(svn_io_remove_file2(tmpfile2, TRUE /*ignore*/, iterpool));
if ((i < (ranges_to_merge->nelts - 1))
&& is_path_conflicted_by_merge(merge_b))
@@ -7092,7 +7097,7 @@ do_file_merge(svn_mergeinfo_catalog_t re
{
const char *mergeinfo_path = svn_client__pathrev_fspath(primary_src,
scratch_pool);
- apr_array_header_t *filtered_rangelist;
+ svn_rangelist_t *filtered_rangelist;
/* Filter any ranges from TARGET_WCPATH's own history, there is no
need to record this explicitly in mergeinfo, it is already part
@@ -7493,7 +7498,7 @@ log_find_operative_subtree_revs(void *ba
Set *OPERATIVE_CHILDREN to a hash (mapping const char * absolute
working copy paths to those path's const char * repos absolute paths)
containing all the immediate subtrees of MERGE_TARGET_ABSPATH which would
- have a different diff applied if MERGE_SOURCE_REPOS_PATH
+ have a different diff applied if MERGE_SOURCE_FSPATH
-r(OLDEST_REV - 1):YOUNGEST_REV were merged to MERGE_TARGET_ABSPATH at
svn_depth_infinity rather than DEPTH.
@@ -7843,7 +7848,7 @@ record_mergeinfo_for_dir_merge(svn_merge
{
const char *child_repos_path;
const char *child_merge_src_fspath;
- apr_array_header_t *child_merge_rangelist;
+ svn_rangelist_t *child_merge_rangelist;
apr_hash_t *child_merges;
svn_client__merge_path_t *child =
APR_ARRAY_IDX(notify_b->children_with_mergeinfo, i,
@@ -7949,7 +7954,7 @@ record_mergeinfo_for_dir_merge(svn_merge
{
svn_error_t *err;
svn_mergeinfo_t subtree_history_as_mergeinfo;
- apr_array_header_t *child_merge_src_rangelist;
+ svn_rangelist_t *child_merge_src_rangelist;
svn_client__pathrev_t *subtree_mergeinfo_pathrev
= svn_client__pathrev_create_with_relpath(
merge_b->target->loc.repos_root_url,
@@ -8110,7 +8115,7 @@ record_mergeinfo_for_added_subtrees(
svn_node_kind_t added_path_kind;
svn_mergeinfo_t merge_mergeinfo;
svn_mergeinfo_t adds_history_as_mergeinfo;
- apr_array_header_t *rangelist;
+ svn_rangelist_t *rangelist;
const char *rel_added_path;
const char *added_path_mergeinfo_fspath;
svn_client__pathrev_t *added_path_pathrev;
@@ -8199,8 +8204,8 @@ typedef struct log_noop_baton_t
/* Initially empty rangelists allocated in POOL. The rangelists are
* populated across multiple invocations of log_noop_revs(). */
- apr_array_header_t *operative_ranges;
- apr_array_header_t *merged_ranges;
+ svn_rangelist_t *operative_ranges;
+ svn_rangelist_t *merged_ranges;
/* Pool to store the rangelists. */
apr_pool_t *pool;
@@ -8217,7 +8222,7 @@ typedef struct log_noop_baton_t
This turns the special case of a single incoming younger range into O(1).
*/
static svn_error_t *
-rangelist_merge_revision(apr_array_header_t *rangelist,
+rangelist_merge_revision(svn_rangelist_t *rangelist,
svn_revnum_t revision,
apr_pool_t *result_pool)
{
@@ -8293,7 +8298,7 @@ log_noop_revs(void *baton,
const char *fspath = svn__apr_hash_index_key(hi);
const char *rel_path;
const char *cwmi_abspath;
- apr_array_header_t *paths_explicit_rangelist = NULL;
+ svn_rangelist_t *paths_explicit_rangelist = NULL;
svn_boolean_t mergeinfo_inherited = FALSE;
/* Adjust REL_PATH so it is relative to the merge source then use it to
@@ -8343,8 +8348,8 @@ log_noop_revs(void *baton,
if (paths_explicit_rangelist)
{
- apr_array_header_t *intersecting_range;
- apr_array_header_t *rangelist;
+ svn_rangelist_t *intersecting_range;
+ svn_rangelist_t *rangelist;
rangelist = svn_rangelist__initialize(revision - 1, revision, TRUE,
scratch_pool);
@@ -8377,7 +8382,7 @@ log_noop_revs(void *baton,
SOURCE is cascaded from the argument of the same name in
do_directory_merge(). TARGET is the merge target. RA_SESSION is the
- session for SOURCE->url2@rev2.
+ session for SOURCE->loc2.
Find all the ranges required by subtrees in
CHILDREN_WITH_MERGEINFO that are *not* required by
@@ -8401,15 +8406,16 @@ remove_noop_subtree_ranges(const merge_s
int i;
svn_client__merge_path_t *root_child =
APR_ARRAY_IDX(children_with_mergeinfo, 0, svn_client__merge_path_t *);
- apr_array_header_t *requested_ranges;
- apr_array_header_t *subtree_gap_ranges;
- apr_array_header_t *subtree_remaining_ranges;
+ svn_rangelist_t *requested_ranges;
+ svn_rangelist_t *subtree_gap_ranges;
+ svn_rangelist_t *subtree_remaining_ranges;
log_noop_baton_t log_gap_baton;
svn_merge_range_t *oldest_gap_rev;
svn_merge_range_t *youngest_gap_rev;
- apr_array_header_t *inoperative_ranges;
+ svn_rangelist_t *inoperative_ranges;
apr_pool_t *iterpool;
+ assert(session_url_is(ra_session, source->loc2->url, scratch_pool));
/* This function is only intended to work with forward merges. */
if (source->loc1->rev > source->loc2->rev)
@@ -8534,7 +8540,7 @@ remove_noop_subtree_ranges(const merge_s
MERGE_B describes the merge being performed. As this function is for a
mergeinfo-aware merge, SOURCE->ancestral should be TRUE, and
- SOURCE->url1@rev1 must be a historical ancestor of SOURCE->url2@rev2, or
+ SOURCE->loc1 must be a historical ancestor of SOURCE->loc2, or
vice-versa (see `MERGEINFO MERGE SOURCE NORMALIZATION' for more
requirements around SOURCE).
@@ -9235,8 +9241,8 @@ do_merge(apr_hash_t **modified_subtrees,
merge (unless this is record-only), followed by record-only merges
to represent the changed mergeinfo.
- The merge is between SOURCE->url1@rev1 (in URL1_RA_SESSION1) and
- SOURCE->url2@rev2 (in URL2_RA_SESSION2); YCA is their youngest
+ The diff to be merged is between SOURCE->loc1 (in URL1_RA_SESSION1)
+ and SOURCE->loc2 (in URL2_RA_SESSION2); YCA is their youngest
common ancestor.
SAME_REPOS must be true if and only if the source URLs are in the same
repository as the target working copy. Other arguments are as in
@@ -9273,6 +9279,9 @@ merge_cousins_and_supplement_mergeinfo(c
subtree mergeinfo, then this will help keep memory use in check. */
apr_pool_t *subpool = svn_pool_create(scratch_pool);
+ assert(session_url_is(URL1_ra_session, source->loc1->url, scratch_pool));
+ assert(session_url_is(URL2_ra_session, source->loc2->url, scratch_pool));
+
SVN_ERR_ASSERT(svn_dirent_is_absolute(target->abspath));
SVN_ERR_ASSERT(! source->ancestral);
@@ -9530,26 +9539,6 @@ open_target_wc(merge_target_t **target_p
return SVN_NO_ERROR;
}
-/* Open an RA session to PATH_OR_URL at PEG_REVISION. Set *RA_SESSION_P to
- * the session and set *LOCATION_P to the resolved revision, URL and
- * repository root. Allocate the results in RESULT_POOL. */
-static svn_error_t *
-open_source_session(svn_client__pathrev_t **location_p,
- svn_ra_session_t **ra_session_p,
- const char *path_or_url,
- const svn_opt_revision_t *peg_revision,
- svn_client_ctx_t *ctx,
- apr_pool_t *result_pool,
- apr_pool_t *scratch_pool)
-{
- SVN_ERR(svn_client__ra_session_from_path2(
- ra_session_p, location_p,
- path_or_url, NULL, peg_revision, peg_revision,
- ctx, result_pool));
- return SVN_NO_ERROR;
-}
-
-
/*-----------------------------------------------------------------------*/
/*** Public APIs ***/
@@ -9594,10 +9583,12 @@ merge_locked(const char *source1,
/* Open RA sessions to both sides of our merge source, and resolve URLs
* and revisions. */
sesspool = svn_pool_create(scratch_pool);
- SVN_ERR(open_source_session(&source1_loc, &ra_session1, source1, revision1,
- ctx, sesspool, scratch_pool));
- SVN_ERR(open_source_session(&source2_loc, &ra_session2, source2, revision2,
- ctx, sesspool, scratch_pool));
+ SVN_ERR(svn_client__ra_session_from_path2(
+ &ra_session1, &source1_loc,
+ source1, NULL, revision1, revision1, ctx, sesspool));
+ SVN_ERR(svn_client__ra_session_from_path2(
+ &ra_session2, &source2_loc,
+ source2, NULL, revision2, revision2, ctx, sesspool));
/* We can't do a diff between different repositories. */
/* ### We should also insist that the root URLs of the two sources match,
@@ -10014,9 +10005,8 @@ log_find_operative_revs(void *baton,
MERGEINFO_CATALOG may be empty if the source has no explicit or inherited
mergeinfo.
- Using RA_SESSION, which is pointed at TARGET_LOC, check that all
- of the unmerged revisions in UNMERGED_CATALOG's mergeinfos are "phantoms",
- that is, one of the following conditions holds:
+ Check that all of the unmerged revisions in UNMERGED_CATALOG's
+ mergeinfos are "phantoms", that is, one of the following conditions holds:
1) The revision affects no corresponding paths in SOURCE_LOC.
@@ -10030,6 +10020,9 @@ log_find_operative_revs(void *baton,
Note: The keys in all mergeinfo catalogs used here are relative to the
root of the repository.
+ RA_SESSION is an RA session open to the repository of TARGET_LOC; it may
+ be temporarily reparented within this function.
+
Use SCRATCH_POOL for all temporary allocations. */
static svn_error_t *
find_unsynced_ranges(const svn_client__pathrev_t *source_loc,
@@ -10041,7 +10034,7 @@ find_unsynced_ranges(const svn_client__p
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
- apr_array_header_t *potentially_unmerged_ranges = NULL;
+ svn_rangelist_t *potentially_unmerged_ranges = NULL;
/* Convert all the unmerged history to a rangelist. */
if (apr_hash_count(unmerged_catalog))
@@ -10076,6 +10069,8 @@ find_unsynced_ranges(const svn_client__p
potentially_unmerged_ranges->nelts - 1,
svn_merge_range_t *))->end;
log_find_operative_baton_t log_baton;
+ const char *old_session_url;
+ svn_error_t *err;
log_baton.merged_catalog = merged_catalog;
log_baton.unmerged_catalog = true_unmerged_catalog;
@@ -10085,10 +10080,14 @@ find_unsynced_ranges(const svn_client__p
= svn_client__pathrev_fspath(target_loc, scratch_pool);
log_baton.result_pool = result_pool;
- SVN_ERR(get_log(ra_session, "", youngest_rev, oldest_rev,
- TRUE, /* discover_changed_paths */
- log_find_operative_revs, &log_baton,
- scratch_pool));
+ SVN_ERR(svn_client__ensure_ra_session_url(
+ &old_session_url, ra_session, target_loc->url, scratch_pool));
+ err = get_log(ra_session, "", youngest_rev, oldest_rev,
+ TRUE, /* discover_changed_paths */
+ log_find_operative_revs, &log_baton,
+ scratch_pool);
+ SVN_ERR(svn_error_compose_create(
+ err, svn_ra_reparent(ra_session, old_session_url, scratch_pool)));
}
return SVN_NO_ERROR;
@@ -10139,6 +10138,9 @@ find_youngest_merged_rev(svn_revnum_t *y
* place, to include the natural history (implicit mergeinfo) of
* SOURCE_PATHREV. ### But make these additions in SCRATCH_POOL.
*
+ * SOURCE_RA_SESSION is an RA session open to the repository containing
+ * SOURCE_PATHREV; it may be temporarily reparented within this function.
+ *
* ### [JAF] This function is named '..._subroutine' simply because I
* factored it out based on code similarity, without knowing what it's
* purpose is. We should clarify its purpose and choose a better name.
@@ -10241,6 +10243,9 @@ find_unmerged_mergeinfo(svn_mergeinfo_ca
svn_mergeinfo_catalog_t new_catalog = apr_hash_make(result_pool);
apr_pool_t *iterpool = svn_pool_create(scratch_pool);
+ assert(session_url_is(source_ra_session, source_loc->url, scratch_pool));
+ assert(session_url_is(target_ra_session, target->loc.url, scratch_pool));
+
*youngest_merged_rev = SVN_INVALID_REVNUM;
/* Examine the natural history of each path in the reintegrate target
@@ -10298,8 +10303,6 @@ find_unmerged_mergeinfo(svn_mergeinfo_ca
exist at all. If simply doesn't exist we can ignore it
altogether. */
svn_node_kind_t kind;
- svn_mergeinfo_catalog_t subtree_catalog;
- apr_array_header_t *source_paths_rel_to_session;
SVN_ERR(svn_ra_check_path(source_ra_session,
path_rel_to_session,
@@ -10309,20 +10312,11 @@ find_unmerged_mergeinfo(svn_mergeinfo_ca
/* Else source_path does exist though it has no explicit mergeinfo.
Find its inherited mergeinfo. If it doesn't have any then simply
set source_mergeinfo to an empty hash. */
- source_paths_rel_to_session =
- apr_array_make(iterpool, 1, sizeof(const char *));
- APR_ARRAY_PUSH(source_paths_rel_to_session, const char *)
- = path_rel_to_session;
- SVN_ERR(svn_ra_get_mergeinfo(source_ra_session, &subtree_catalog,
- source_paths_rel_to_session,
- source_loc->rev, svn_mergeinfo_inherited,
- FALSE, iterpool));
- if (subtree_catalog)
- source_mergeinfo = apr_hash_get(subtree_catalog,
- path_rel_to_session,
- APR_HASH_KEY_STRING);
-
- /* A path might not have any inherited mergeinfo either. */
+ SVN_ERR(svn_client__get_repos_mergeinfo(
+ &source_mergeinfo, source_ra_session,
+ source_pathrev->url, source_pathrev->rev,
+ svn_mergeinfo_inherited, FALSE /*squelch_incapable*/,
+ iterpool));
if (!source_mergeinfo)
source_mergeinfo = apr_hash_make(iterpool);
}
@@ -10476,8 +10470,6 @@ calculate_left_hand_side(svn_client__pat
apr_pool_t *scratch_pool)
{
svn_mergeinfo_catalog_t mergeinfo_catalog, unmerged_catalog;
- apr_array_header_t *source_repos_rel_path_as_array
- = apr_array_make(scratch_pool, 1, sizeof(const char *));
apr_pool_t *iterpool = svn_pool_create(scratch_pool);
apr_hash_index_t *hi;
/* hash of paths mapped to arrays of svn_mergeinfo_t. */
@@ -10485,6 +10477,9 @@ calculate_left_hand_side(svn_client__pat
svn_revnum_t youngest_merged_rev;
svn_client__pathrev_t *yc_ancestor;
+ assert(session_url_is(source_ra_session, source_loc->url, scratch_pool));
+ assert(session_url_is(target_ra_session, target->loc.url, scratch_pool));
+
/* Initialize our return variables. */
*left_p = NULL;
@@ -10553,18 +10548,11 @@ calculate_left_hand_side(svn_client__pat
/* Get the mergeinfo from the source, including its descendants
with differing explicit mergeinfo. */
- APR_ARRAY_PUSH(source_repos_rel_path_as_array, const char *) = "";
- SVN_ERR(svn_ra_get_mergeinfo(source_ra_session, &mergeinfo_catalog,
- source_repos_rel_path_as_array, source_loc->rev,
- svn_mergeinfo_inherited,
- TRUE, iterpool));
-
- if (mergeinfo_catalog)
- SVN_ERR(svn_mergeinfo__add_prefix_to_catalog(&mergeinfo_catalog,
- mergeinfo_catalog,
- svn_client__pathrev_relpath(
- source_loc, iterpool),
- iterpool, iterpool));
+ SVN_ERR(svn_client__get_repos_mergeinfo_catalog(
+ &mergeinfo_catalog, source_ra_session,
+ source_loc->url, source_loc->rev,
+ svn_mergeinfo_inherited, FALSE /* squelch_incapable */,
+ TRUE /* include_descendants */, iterpool, iterpool));
if (!mergeinfo_catalog)
mergeinfo_catalog = apr_hash_make(iterpool);
@@ -10613,11 +10601,10 @@ calculate_left_hand_side(svn_client__pat
}
/* Determine the URLs and revisions needed to perform a reintegrate merge
- * from SOURCE_PATH_OR_URL at SOURCE_PEG_REVISION into the working
- * copy at TARGET.
+ * from SOURCE_LOC into the working copy at TARGET.
*
* SOURCE_RA_SESSION and TARGET_RA_SESSION are RA sessions opened to the
- * source and target branches respectively.
+ * URLs of SOURCE_LOC and TARGET->loc respectively.
*
* Set *SOURCE_P to
* the source-left and source-right locations of the required merge. Set
@@ -10645,6 +10632,9 @@ find_reintegrate_merge(merge_source_t **
svn_error_t *err;
apr_hash_t *subtrees_with_mergeinfo;
+ assert(session_url_is(source_ra_session, source_loc->url, scratch_pool));
+ assert(session_url_is(target_ra_session, target->loc.url, scratch_pool));
+
/* As the WC tree is "pure", use its last-updated-to revision as
the default revision for the left side of our merge, since that's
what the repository sub-tree is required to be up to date with
@@ -10806,9 +10796,10 @@ open_reintegrate_source_and_target(svn_r
svn_dirent_local_style(target->abspath,
scratch_pool));
- SVN_ERR(open_source_session(&source_loc, source_ra_session_p,
- source_path_or_url, source_peg_revision,
- ctx, result_pool, scratch_pool));
+ SVN_ERR(svn_client__ra_session_from_path2(
+ source_ra_session_p, &source_loc,
+ source_path_or_url, NULL, source_peg_revision, source_peg_revision,
+ ctx, result_pool));
/* source_loc and target->loc are required to be in the same repository,
as mergeinfo doesn't come into play for cross-repository merging. */
@@ -10967,7 +10958,7 @@ svn_client_merge_reintegrate(const char
static svn_error_t *
merge_peg_locked(const char *source_path_or_url,
const svn_opt_revision_t *source_peg_revision,
- const apr_array_header_t *ranges_to_merge,
+ const svn_rangelist_t *ranges_to_merge,
const char *target_abspath,
svn_depth_t depth,
svn_boolean_t ignore_ancestry,
@@ -10998,9 +10989,10 @@ merge_peg_locked(const char *source_path
ctx, sesspool, sesspool));
/* Open an RA session to our source URL, and determine its root URL. */
- SVN_ERR(open_source_session(&source_loc, &ra_session,
- source_path_or_url, source_peg_revision,
- ctx, sesspool, sesspool));
+ SVN_ERR(svn_client__ra_session_from_path2(
+ &ra_session, &source_loc,
+ source_path_or_url, NULL, source_peg_revision, source_peg_revision,
+ ctx, sesspool));
/* Normalize our merge sources. */
SVN_ERR(normalize_merge_sources(&merge_sources, source_path_or_url,
@@ -11069,7 +11061,6 @@ svn_client_merge_peg4(const char *source
return SVN_NO_ERROR;
}
-#ifdef SVN_WITH_SYMMETRIC_MERGE
/* The location-history of a branch.
*
@@ -11105,7 +11096,7 @@ location_on_branch_at_rev(const branch_h
hi = apr_hash_next(hi))
{
const char *fspath = svn__apr_hash_index_key(hi);
- apr_array_header_t *rangelist = svn__apr_hash_index_val(hi);
+ svn_rangelist_t *rangelist = svn__apr_hash_index_val(hi);
int i;
for (i = 0; i < rangelist->nelts; i++)
@@ -11123,12 +11114,6 @@ location_on_branch_at_rev(const branch_h
return NULL;
}
-/* Details of a symmetric merge. */
-struct svn_client__symmetric_merge_t
-{
- svn_client__pathrev_t *yca, *base, *mid, *right;
-};
-
/* */
typedef struct source_and_target_t
{
@@ -11152,56 +11137,6 @@ typedef struct source_and_target_t
svn_client__pathrev_t *yca;
} source_and_target_t;
-/* "Open" the source and target branches of a merge. That means:
- * - find out their exact repository locations (resolve WC paths and
- * non-numeric revision numbers),
- * - check the branches are suitably related,
- * - establish RA session(s) to the repo,
- * - check the WC for suitability (throw an error if unsuitable)
- *
- * Record this information and return it in a new "merge context" object.
- */
-static svn_error_t *
-open_source_and_target(source_and_target_t **source_and_target,
- const char *source_path_or_url,
- const svn_opt_revision_t *source_peg_revision,
- const char *target_abspath,
- svn_boolean_t allow_mixed_rev,
- svn_boolean_t allow_local_mods,
- svn_boolean_t allow_switched_subtrees,
- svn_client_ctx_t *ctx,
- apr_pool_t *session_pool,
- apr_pool_t *result_pool,
- apr_pool_t *scratch_pool)
-{
- source_and_target_t *s_t = apr_palloc(result_pool, sizeof(*s_t));
-
- /* Target */
- SVN_ERR(open_target_wc(&s_t->target, target_abspath,
- allow_mixed_rev, allow_local_mods, allow_switched_subtrees,
- ctx, result_pool, scratch_pool));
- SVN_ERR(svn_client_open_ra_session(&s_t->target_ra_session,
- s_t->target->loc.url,
- ctx, session_pool));
-
- /* Source */
- SVN_ERR(open_source_session(&s_t->source, &s_t->source_ra_session,
- source_path_or_url, source_peg_revision,
- ctx, result_pool, scratch_pool));
-
- *source_and_target = s_t;
- return SVN_NO_ERROR;
-}
-
-/* "Close" any resources that were acquired in the S_T structure. */
-static svn_error_t *
-close_source_and_target(source_and_target_t *s_t,
- apr_pool_t *scratch_pool)
-{
- /* close s_t->source_/target_ra_session */
- return SVN_NO_ERROR;
-}
-
/* Set *INTERSECTION_P to the intersection of BRANCH_HISTORY with the
* revision range OLDEST_REV to YOUNGEST_REV (inclusive).
*
@@ -11466,10 +11401,10 @@ find_base_on_target(svn_client__pathrev_
return SVN_NO_ERROR;
}
-/* The body of svn_client__find_symmetric_merge(), which see.
+/* The body of svn_client_find_automatic_merge(), which see.
*/
static svn_error_t *
-find_symmetric_merge(svn_client__pathrev_t **base_p,
+find_automatic_merge(svn_client__pathrev_t **base_p,
svn_client__pathrev_t **mid_p,
source_and_target_t *s_t,
svn_client_ctx_t *ctx,
@@ -11486,14 +11421,23 @@ find_symmetric_merge(svn_client__pathrev
svn_mergeinfo_inherited,
FALSE /* squelch_incapable */,
scratch_pool));
- SVN_ERR(svn_client__get_wc_or_repos_mergeinfo(&s_t->target_mergeinfo,
- NULL /* inherited */,
- NULL /* from_repos */,
- FALSE /* repos_only */,
- svn_mergeinfo_inherited,
- s_t->target_ra_session,
- s_t->target->abspath,
- ctx, scratch_pool));
+ if (! s_t->target->abspath)
+ SVN_ERR(svn_client__get_repos_mergeinfo(&s_t->target_mergeinfo,
+ s_t->target_ra_session,
+ s_t->target->loc.url,
+ s_t->target->loc.rev,
+ svn_mergeinfo_inherited,
+ FALSE /* squelch_incapable */,
+ scratch_pool));
+ else
+ SVN_ERR(svn_client__get_wc_or_repos_mergeinfo(&s_t->target_mergeinfo,
+ NULL /* inherited */,
+ NULL /* from_repos */,
+ FALSE /* repos_only */,
+ svn_mergeinfo_inherited,
+ s_t->target_ra_session,
+ s_t->target->abspath,
+ ctx, scratch_pool));
/* Get the location-history of each branch. */
s_t->source_branch.tip = s_t->source;
@@ -11537,45 +11481,114 @@ find_symmetric_merge(svn_client__pathrev
return SVN_NO_ERROR;
}
+/* Details of an automatic merge. */
+struct svn_client_automatic_merge_t
+{
+ svn_client__pathrev_t *yca, *base, *mid, *right, *target;
+ svn_boolean_t allow_mixed_rev, allow_local_mods, allow_switched_subtrees;
+};
+
svn_error_t *
-svn_client__find_symmetric_merge(svn_client__symmetric_merge_t **merge_p,
+svn_client_find_automatic_merge_no_wc(
+ svn_client_automatic_merge_t **merge_p,
const char *source_path_or_url,
const svn_opt_revision_t *source_revision,
- const char *target_wcpath,
- svn_boolean_t allow_mixed_rev,
- svn_boolean_t allow_local_mods,
- svn_boolean_t allow_switched_subtrees,
+ const char *target_path_or_url,
+ const svn_opt_revision_t *target_revision,
svn_client_ctx_t *ctx,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
+ source_and_target_t *s_t = apr_palloc(scratch_pool, sizeof(*s_t));
+ svn_client__pathrev_t *target_loc;
+ svn_client_automatic_merge_t *merge = apr_palloc(result_pool, sizeof(*merge));
+
+ /* Source */
+ SVN_ERR(svn_client__ra_session_from_path2(
+ &s_t->source_ra_session, &s_t->source,
+ source_path_or_url, NULL, source_revision, source_revision,
+ ctx, result_pool));
+
+ /* Target */
+ SVN_ERR(svn_client__ra_session_from_path2(
+ &s_t->target_ra_session, &target_loc,
+ target_path_or_url, NULL, target_revision, target_revision,
+ ctx, result_pool));
+ s_t->target = apr_palloc(scratch_pool, sizeof(*s_t->target));
+ s_t->target->kind = svn_node_none;
+ s_t->target->abspath = NULL; /* indicate the target is not a WC */
+ s_t->target->loc = *target_loc;
+
+ SVN_ERR(find_automatic_merge(&merge->base, &merge->mid, s_t,
+ ctx, result_pool, scratch_pool));
+
+ merge->right = s_t->source;
+ merge->target = &s_t->target->loc;
+ merge->yca = s_t->yca;
+ *merge_p = merge;
+
+ return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_client_find_automatic_merge(svn_client_automatic_merge_t **merge_p,
+ const char *source_path_or_url,
+ const svn_opt_revision_t *source_revision,
+ const char *target_wcpath,
+ svn_boolean_t allow_mixed_rev,
+ svn_boolean_t allow_local_mods,
+ svn_boolean_t allow_switched_subtrees,
+ svn_client_ctx_t *ctx,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
const char *target_abspath;
- source_and_target_t *s_t;
- svn_client__symmetric_merge_t *merge = apr_palloc(result_pool, sizeof(*merge));
+ source_and_target_t *s_t = apr_palloc(result_pool, sizeof(*s_t));
+ svn_client_automatic_merge_t *merge = apr_palloc(result_pool, sizeof(*merge));
SVN_ERR(svn_dirent_get_absolute(&target_abspath, target_wcpath, scratch_pool));
- SVN_ERR(open_source_and_target(&s_t, source_path_or_url, source_revision,
- target_abspath, allow_mixed_rev, allow_local_mods, allow_switched_subtrees,
- ctx, result_pool, result_pool, scratch_pool));
+
+ /* "Open" the target WC. We're not going to check the target WC for
+ * mixed-rev, local mods or switched subtrees yet. After we find out
+ * what kind of merge is required, then if a reintegrate-like merge is
+ * required we'll do the stricter checks, in do_automatic_merge_locked(). */
+ SVN_ERR(open_target_wc(&s_t->target, target_abspath,
+ TRUE /*allow_mixed_rev*/,
+ TRUE /*allow_local_mods*/,
+ TRUE /*allow_switched_subtrees*/,
+ ctx, result_pool, scratch_pool));
+
+ /* Open RA sessions to the source and target trees. */
+ SVN_ERR(svn_client_open_ra_session(&s_t->target_ra_session,
+ s_t->target->loc.url,
+ ctx, result_pool));
+ /* ### check for null URL (i.e. added path) here, like in reintegrate? */
+ SVN_ERR(svn_client__ra_session_from_path2(
+ &s_t->source_ra_session, &s_t->source,
+ source_path_or_url, NULL, source_revision, source_revision,
+ ctx, result_pool));
/* Check source is in same repos as target. */
SVN_ERR(check_same_repos(s_t->source, source_path_or_url,
&s_t->target->loc, target_wcpath,
TRUE /* strict_urls */, scratch_pool));
- SVN_ERR(find_symmetric_merge(&merge->base, &merge->mid, s_t,
+ SVN_ERR(find_automatic_merge(&merge->base, &merge->mid, s_t,
ctx, result_pool, scratch_pool));
merge->yca = s_t->yca;
merge->right = s_t->source;
+ merge->allow_mixed_rev = allow_mixed_rev;
+ merge->allow_local_mods = allow_local_mods;
+ merge->allow_switched_subtrees = allow_switched_subtrees;
*merge_p = merge;
- SVN_ERR(close_source_and_target(s_t, scratch_pool));
+ /* TODO: Close the source and target sessions here? */
return SVN_NO_ERROR;
}
-/* The body of svn_client__do_symmetric_merge(), which see.
+/* The body of svn_client_do_automatic_merge(), which see.
*
* Five locations are inputs: YCA, BASE, MID, RIGHT, TARGET, as shown
* depending on whether the base is on the source branch or the target
@@ -11603,10 +11616,9 @@ svn_client__find_symmetric_merge(svn_cli
* eliminate already-cherry-picked revisions from the source.
*/
static svn_error_t *
-do_symmetric_merge_locked(const svn_client__symmetric_merge_t *merge,
+do_automatic_merge_locked(const svn_client_automatic_merge_t *merge,
const char *target_abspath,
svn_depth_t depth,
- svn_boolean_t ignore_ancestry,
svn_boolean_t force,
svn_boolean_t record_only,
svn_boolean_t dry_run,
@@ -11615,29 +11627,71 @@ do_symmetric_merge_locked(const svn_clie
apr_pool_t *scratch_pool)
{
merge_target_t *target;
+ svn_boolean_t reintegrate_like = (merge->mid != NULL);
svn_boolean_t use_sleep = FALSE;
svn_error_t *err;
- SVN_ERR(open_target_wc(&target, target_abspath, TRUE, TRUE, TRUE,
+ SVN_ERR(open_target_wc(&target, target_abspath,
+ merge->allow_mixed_rev && ! reintegrate_like,
+ merge->allow_local_mods && ! reintegrate_like,
+ merge->allow_switched_subtrees && ! reintegrate_like,
ctx, scratch_pool, scratch_pool));
- if (merge->mid)
+ if (reintegrate_like)
{
merge_source_t source;
- svn_ra_session_t *ra_session = NULL;
+ svn_ra_session_t *base_ra_session = NULL;
+ svn_ra_session_t *right_ra_session = NULL;
+ svn_ra_session_t *target_ra_session = NULL;
+
+ if (record_only)
+ return svn_error_create(SVN_ERR_INCORRECT_PARAMS, NULL,
+ _("The required merge is reintegrate-like, "
+ "and the record-only option "
+ "cannot be used with this kind of merge"));
+
+ if (depth != svn_depth_unknown)
+ return svn_error_create(SVN_ERR_INCORRECT_PARAMS, NULL,
+ _("The required merge is reintegrate-like, "
+ "and the depth option "
+ "cannot be used with this kind of merge"));
+
+ if (force)
+ return svn_error_create(SVN_ERR_INCORRECT_PARAMS, NULL,
+ _("The required merge is reintegrate-like, "
+ "and the force option "
+ "cannot be used with this kind of merge"));
+
+ SVN_ERR(ensure_ra_session_url(&base_ra_session, merge->base->url,
+ ctx, scratch_pool));
+ SVN_ERR(ensure_ra_session_url(&right_ra_session, merge->right->url,
+ ctx, scratch_pool));
+ SVN_ERR(ensure_ra_session_url(&target_ra_session, target->loc.url,
+ ctx, scratch_pool));
+
+ /* Check for and reject any abnormalities -- such as revisions that
+ * have not yet been merged in the opposite direction -- that a
+ * 'reintegrate' merge would have rejected. */
+ {
+ merge_source_t *source2;
+
+ SVN_ERR(find_reintegrate_merge(&source2, NULL,
+ right_ra_session, merge->right,
+ target_ra_session, target,
+ ctx, scratch_pool, scratch_pool));
+ }
source.loc1 = merge->base;
source.loc2 = merge->right;
source.ancestral = (merge->mid == NULL);
- SVN_ERR(ensure_ra_session_url(&ra_session, source.loc1->url,
- ctx, scratch_pool));
-
err = merge_cousins_and_supplement_mergeinfo(target,
- ra_session, ra_session,
+ base_ra_session,
+ right_ra_session,
&source, merge->yca,
TRUE /* same_repos */,
- depth, ignore_ancestry,
+ depth,
+ FALSE /*ignore_ancestry*/,
force, record_only,
dry_run,
merge_options, &use_sleep,
@@ -11652,7 +11706,7 @@ do_symmetric_merge_locked(const svn_clie
gaps that are older than the base that we calculated (which is
for the root path of the merge).
- An improvement would be to change find_symmetric_merge() to
+ An improvement would be to change find_automatic_merge() to
find the base for each sutree, and then here use the oldest base
among all subtrees. */
merge_source_t source;
@@ -11666,8 +11720,8 @@ do_symmetric_merge_locked(const svn_clie
APR_ARRAY_PUSH(merge_sources, const merge_source_t *) = &source;
err = do_merge(NULL, NULL, merge_sources, target, NULL,
- TRUE /*related*/,
- TRUE /*same_repos*/, ignore_ancestry, force, dry_run,
+ TRUE /*related*/, TRUE /*same_repos*/,
+ FALSE /*ignore_ancestry*/, force, dry_run,
record_only, NULL, FALSE, FALSE, depth, merge_options,
&use_sleep, ctx, scratch_pool, scratch_pool);
}
@@ -11681,16 +11735,15 @@ do_symmetric_merge_locked(const svn_clie
}
svn_error_t *
-svn_client__do_symmetric_merge(const svn_client__symmetric_merge_t *merge,
- 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)
+svn_client_do_automatic_merge(const svn_client_automatic_merge_t *merge,
+ const char *target_wcpath,
+ svn_depth_t depth,
+ 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)
{
const char *target_abspath, *lock_abspath;
@@ -11699,18 +11752,43 @@ svn_client__do_symmetric_merge(const svn
if (!dry_run)
SVN_WC__CALL_WITH_WRITE_LOCK(
- do_symmetric_merge_locked(merge,
- target_abspath, depth, ignore_ancestry,
+ do_automatic_merge_locked(merge,
+ target_abspath, depth,
force, record_only, dry_run,
merge_options, ctx, pool),
ctx->wc_ctx, lock_abspath, FALSE /* lock_anchor */, pool);
else
- SVN_ERR(do_symmetric_merge_locked(merge,
- target_abspath, depth, ignore_ancestry,
+ SVN_ERR(do_automatic_merge_locked(merge,
+ target_abspath, depth,
force, record_only, dry_run,
merge_options, ctx, pool));
return SVN_NO_ERROR;
}
-#endif /* SVN_WITH_SYMMETRIC_MERGE */
+svn_boolean_t
+svn_client_automatic_merge_is_reintegrate_like(
+ const svn_client_automatic_merge_t *merge)
+{
+ return merge->mid != NULL;
+}
+
+svn_error_t *
+svn_client__automatic_merge_get_locations(
+ svn_client__pathrev_t **yca,
+ svn_client__pathrev_t **base,
+ svn_client__pathrev_t **right,
+ svn_client__pathrev_t **target,
+ const svn_client_automatic_merge_t *merge,
+ apr_pool_t *result_pool)
+{
+ if (yca)
+ *yca = svn_client__pathrev_dup(merge->yca, result_pool);
+ if (base)
+ *base = svn_client__pathrev_dup(merge->base, result_pool);
+ if (right)
+ *right = svn_client__pathrev_dup(merge->right, result_pool);
+ if (target)
+ *target = svn_client__pathrev_dup(merge->target, result_pool);
+ return SVN_NO_ERROR;
+}