diff options
author | peter <peter@FreeBSD.org> | 2013-07-28 05:04:41 +0000 |
---|---|---|
committer | peter <peter@FreeBSD.org> | 2013-07-28 05:04:41 +0000 |
commit | 3b9f7e96381479fb03ae2c36d490a38718f71083 (patch) | |
tree | a851d66ec0c51a7321b30a677a0e55f1655af4d6 /subversion/libsvn_client | |
parent | 6879a90da0ad9b5e74fc212c899751fe3821ac7b (diff) | |
download | FreeBSD-src-3b9f7e96381479fb03ae2c36d490a38718f71083.zip FreeBSD-src-3b9f7e96381479fb03ae2c36d490a38718f71083.tar.gz |
Import subversion-1.8.1 into vendor staging area.
Diffstat (limited to 'subversion/libsvn_client')
-rw-r--r-- | subversion/libsvn_client/client.h | 64 | ||||
-rw-r--r-- | subversion/libsvn_client/commit.c | 7 | ||||
-rw-r--r-- | subversion/libsvn_client/copy.c | 17 | ||||
-rw-r--r-- | subversion/libsvn_client/diff.c | 57 | ||||
-rw-r--r-- | subversion/libsvn_client/diff_local.c | 12 | ||||
-rw-r--r-- | subversion/libsvn_client/log.c | 45 | ||||
-rw-r--r-- | subversion/libsvn_client/merge.c | 65 | ||||
-rw-r--r-- | subversion/libsvn_client/mergeinfo.c | 102 | ||||
-rw-r--r-- | subversion/libsvn_client/ra.c | 104 | ||||
-rw-r--r-- | subversion/libsvn_client/switch.c | 2 |
10 files changed, 345 insertions, 130 deletions
diff --git a/subversion/libsvn_client/client.h b/subversion/libsvn_client/client.h index 9ea25f2..f136888 100644 --- a/subversion/libsvn_client/client.h +++ b/subversion/libsvn_client/client.h @@ -20,7 +20,8 @@ * under the License. * ==================================================================== */ - + + #ifndef SVN_LIBSVN_CLIENT_H #define SVN_LIBSVN_CLIENT_H @@ -208,6 +209,9 @@ svn_client__repos_location_segments(apr_array_header_t **segments, Use the authentication baton cached in CTX to authenticate against the repository. Use POOL for all allocations. + See also svn_client__calc_youngest_common_ancestor() to find youngest + common ancestor for already fetched history-as-mergeinfo information. + See also svn_client__youngest_common_ancestor(). */ svn_error_t * @@ -219,6 +223,34 @@ svn_client__get_youngest_common_ancestor(svn_client__pathrev_t **ancestor_p, apr_pool_t *result_pool, apr_pool_t *scratch_pool); +/* Find the common ancestor of two locations in a repository using already + fetched history-as-mergeinfo information. + + Ancestry is determined by the 'copy-from' relationship and the normal + successor relationship. + + Set *ANCESTOR_P to the location of the youngest common ancestor of + LOC1 and LOC2. If the locations have no common ancestor (including if + they don't have the same repository root URL), set *ANCESTOR_P to NULL. + + HISTORY1, HAS_REV_ZERO_HISTORY1, HISTORY2, HAS_REV_ZERO_HISTORY2 are + history-as-mergeinfo information as returned by + svn_client__get_history_as_mergeinfo() for LOC1 and LOC2 respectively. + + See also svn_client__get_youngest_common_ancestor(). + +*/ +svn_error_t * +svn_client__calc_youngest_common_ancestor(svn_client__pathrev_t **ancestor_p, + const svn_client__pathrev_t *loc1, + apr_hash_t *history1, + svn_boolean_t has_rev_zero_history1, + const svn_client__pathrev_t *loc2, + apr_hash_t *history2, + svn_boolean_t has_rev_zero_history2, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool); + /* Ensure that RA_SESSION's session URL matches SESSION_URL, reparenting that session if necessary. Store the previous session URL in *OLD_SESSION_URL (so that if the @@ -247,7 +279,8 @@ svn_client__ensure_ra_session_url(const char **old_session_url, apr_pool_t *pool); /* ---------------------------------------------------------------- */ - + + /*** RA callbacks ***/ @@ -329,7 +362,8 @@ svn_client__ra_make_cb_baton(svn_wc_context_t *wc_ctx, apr_pool_t *result_pool); /* ---------------------------------------------------------------- */ - + + /*** Add/delete ***/ /* If AUTOPROPS is not null: Then read automatic properties matching PATH @@ -442,7 +476,8 @@ svn_client__make_local_parents(const char *path, apr_pool_t *pool); /* ---------------------------------------------------------------- */ - + + /*** Checkout, update and switch ***/ /* Update a working copy LOCAL_ABSPATH to REVISION, and (if not NULL) set @@ -581,7 +616,8 @@ svn_client__switch_internal(svn_revnum_t *result_rev, apr_pool_t *pool); /* ---------------------------------------------------------------- */ - + + /*** Inheritable Properties ***/ /* Convert any svn_prop_inherited_item_t elements in INHERITED_PROPS which @@ -626,7 +662,8 @@ svn_client__get_inheritable_props(apr_hash_t **wcroot_iprops, apr_pool_t *scratch_pool); /* ---------------------------------------------------------------- */ - + + /*** Editor for repository diff ***/ /* Create an editor for a pure repository comparison, i.e. comparing one @@ -666,7 +703,8 @@ svn_client__get_diff_editor2(const svn_delta_editor_t **editor, apr_pool_t *result_pool); /* ---------------------------------------------------------------- */ - + + /*** Editor for diff summary ***/ /* Set *CALLBACKS and *CALLBACK_BATON to a set of diff callbacks that will @@ -689,7 +727,8 @@ svn_client__get_diff_summarize_callbacks( apr_pool_t *pool); /* ---------------------------------------------------------------- */ - + + /*** Copy Stuff ***/ /* This structure is used to associate a specific copy or move SRC with a @@ -730,7 +769,8 @@ typedef struct svn_client__copy_pair_t } svn_client__copy_pair_t; /* ---------------------------------------------------------------- */ - + + /*** Commit Stuff ***/ /* WARNING: This is all new, untested, un-peer-reviewed conceptual @@ -944,7 +984,8 @@ svn_client__do_commit(const char *base_url, apr_pool_t *scratch_pool); - + + /*** Externals (Modules) ***/ /* Handle changes to the svn:externals property described by EXTERNALS_NEW, @@ -1116,7 +1157,8 @@ svn_client__resolve_conflicts(svn_boolean_t *conflicts_remain, svn_client_ctx_t *ctx, apr_pool_t *scratch_pool); - + + #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/subversion/libsvn_client/commit.c b/subversion/libsvn_client/commit.c index 3f6bfef..6b30885 100644 --- a/subversion/libsvn_client/commit.c +++ b/subversion/libsvn_client/commit.c @@ -240,6 +240,13 @@ post_process_commit_item(svn_wc_committed_queue_t *queue, remove_lock = (! keep_locks && (item->state_flags & SVN_CLIENT_COMMIT_ITEM_LOCK_TOKEN)); + /* When the node was deleted (or replaced), we need to always remove the + locks, as they're invalidated on the server. We cannot honor the + SVN_CLIENT_COMMIT_ITEM_LOCK_TOKEN flag here because it does not tell + us whether we have locked children. */ + if (item->state_flags & SVN_CLIENT_COMMIT_ITEM_DELETE) + remove_lock = TRUE; + return svn_wc_queue_committed3(queue, wc_ctx, item->path, loop_recurse, item->incoming_prop_changes, remove_lock, !keep_changelists, diff --git a/subversion/libsvn_client/copy.c b/subversion/libsvn_client/copy.c index c0501b9..000ae0c 100644 --- a/subversion/libsvn_client/copy.c +++ b/subversion/libsvn_client/copy.c @@ -385,6 +385,7 @@ static svn_error_t * verify_wc_dsts(const apr_array_header_t *copy_pairs, svn_boolean_t make_parents, svn_boolean_t is_move, + svn_boolean_t metadata_only, svn_client_ctx_t *ctx, apr_pool_t *result_pool, apr_pool_t *scratch_pool) @@ -435,8 +436,11 @@ verify_wc_dsts(const apr_array_header_t *copy_pairs, } /* Check that there is no unversioned obstruction */ - SVN_ERR(svn_io_check_path(pair->dst_abspath_or_url, &dst_kind, - iterpool)); + if (metadata_only) + dst_kind = svn_node_none; + else + SVN_ERR(svn_io_check_path(pair->dst_abspath_or_url, &dst_kind, + iterpool)); if (dst_kind != svn_node_none) { @@ -527,6 +531,7 @@ static svn_error_t * verify_wc_srcs_and_dsts(const apr_array_header_t *copy_pairs, svn_boolean_t make_parents, svn_boolean_t is_move, + svn_boolean_t metadata_only, svn_client_ctx_t *ctx, apr_pool_t *result_pool, apr_pool_t *scratch_pool) @@ -557,7 +562,7 @@ verify_wc_srcs_and_dsts(const apr_array_header_t *copy_pairs, scratch_pool)); } - SVN_ERR(verify_wc_dsts(copy_pairs, make_parents, is_move, ctx, + SVN_ERR(verify_wc_dsts(copy_pairs, make_parents, is_move, metadata_only, ctx, result_pool, iterpool)); svn_pool_destroy(iterpool); @@ -1727,8 +1732,8 @@ repos_to_wc_copy_locked(svn_boolean_t *timestamp_sleep, /* We've already checked for physical obstruction by a working file. But there could also be logical obstruction by an entry whose working file happens to be missing.*/ - SVN_ERR(verify_wc_dsts(copy_pairs, FALSE, FALSE, ctx, - scratch_pool, iterpool)); + SVN_ERR(verify_wc_dsts(copy_pairs, FALSE, FALSE, FALSE /* metadata_only */, + ctx, scratch_pool, iterpool)); /* Decide whether the two repositories are the same or not. */ { @@ -2210,7 +2215,7 @@ try_copy(svn_boolean_t *timestamp_sleep, if ((! srcs_are_urls) && (! dst_is_url)) { SVN_ERR(verify_wc_srcs_and_dsts(copy_pairs, make_parents, is_move, - ctx, pool, pool)); + metadata_only, ctx, pool, pool)); /* Copy or move all targets. */ if (is_move) diff --git a/subversion/libsvn_client/diff.c b/subversion/libsvn_client/diff.c index a5a36bd..26890ae 100644 --- a/subversion/libsvn_client/diff.c +++ b/subversion/libsvn_client/diff.c @@ -51,6 +51,7 @@ #include "private/svn_wc_private.h" #include "private/svn_diff_private.h" #include "private/svn_subr_private.h" +#include "private/svn_io_private.h" #include "svn_private_config.h" @@ -807,14 +808,23 @@ diff_content_changed(svn_boolean_t *wrote_header, * ### a non-git compatible diff application.*/ /* We deal in streams, but svn_io_run_diff2() deals in file handles, - unfortunately, so we need to make these temporary files, and then - copy the contents to our stream. */ - SVN_ERR(svn_io_open_unique_file3(&outfile, &outfilename, NULL, - svn_io_file_del_on_pool_cleanup, - scratch_pool, scratch_pool)); - SVN_ERR(svn_io_open_unique_file3(&errfile, &errfilename, NULL, - svn_io_file_del_on_pool_cleanup, - scratch_pool, scratch_pool)); + so we may need to make temporary files and then copy the contents + to our stream. */ + outfile = svn_stream__aprfile(outstream); + if (outfile) + outfilename = NULL; + else + SVN_ERR(svn_io_open_unique_file3(&outfile, &outfilename, NULL, + svn_io_file_del_on_pool_cleanup, + scratch_pool, scratch_pool)); + + errfile = svn_stream__aprfile(errstream); + if (errfile) + errfilename = NULL; + else + SVN_ERR(svn_io_open_unique_file3(&errfile, &errfilename, NULL, + svn_io_file_del_on_pool_cleanup, + scratch_pool, scratch_pool)); SVN_ERR(svn_io_run_diff2(".", diff_cmd_baton->options.for_external.argv, @@ -824,20 +834,25 @@ diff_content_changed(svn_boolean_t *wrote_header, &exitcode, outfile, errfile, diff_cmd_baton->diff_cmd, scratch_pool)); - SVN_ERR(svn_io_file_close(outfile, scratch_pool)); - SVN_ERR(svn_io_file_close(errfile, scratch_pool)); - /* Now, open and copy our files to our output streams. */ - SVN_ERR(svn_stream_open_readonly(&stream, outfilename, - scratch_pool, scratch_pool)); - SVN_ERR(svn_stream_copy3(stream, svn_stream_disown(outstream, - scratch_pool), - NULL, NULL, scratch_pool)); - SVN_ERR(svn_stream_open_readonly(&stream, errfilename, - scratch_pool, scratch_pool)); - SVN_ERR(svn_stream_copy3(stream, svn_stream_disown(errstream, - scratch_pool), - NULL, NULL, scratch_pool)); + if (outfilename) + { + SVN_ERR(svn_io_file_close(outfile, scratch_pool)); + SVN_ERR(svn_stream_open_readonly(&stream, outfilename, + scratch_pool, scratch_pool)); + SVN_ERR(svn_stream_copy3(stream, svn_stream_disown(outstream, + scratch_pool), + NULL, NULL, scratch_pool)); + } + if (errfilename) + { + SVN_ERR(svn_io_file_close(errfile, scratch_pool)); + SVN_ERR(svn_stream_open_readonly(&stream, errfilename, + scratch_pool, scratch_pool)); + SVN_ERR(svn_stream_copy3(stream, svn_stream_disown(errstream, + scratch_pool), + NULL, NULL, scratch_pool)); + } /* We have a printed a diff for this path, mark it as visited. */ *wrote_header = TRUE; diff --git a/subversion/libsvn_client/diff_local.c b/subversion/libsvn_client/diff_local.c index cc7184f..2dd8a1b 100644 --- a/subversion/libsvn_client/diff_local.c +++ b/subversion/libsvn_client/diff_local.c @@ -607,7 +607,10 @@ svn_client__arbitrary_nodes_diff(const char *local_abspath1, if (kind1 != kind2) return svn_error_createf(SVN_ERR_NODE_UNEXPECTED_KIND, NULL, _("'%s' is not the same node kind as '%s'"), - local_abspath1, local_abspath2); + svn_dirent_local_style(local_abspath1, + scratch_pool), + svn_dirent_local_style(local_abspath2, + scratch_pool)); if (depth == svn_depth_unknown) depth = svn_depth_infinity; @@ -627,7 +630,10 @@ svn_client__arbitrary_nodes_diff(const char *local_abspath1, else return svn_error_createf(SVN_ERR_NODE_UNEXPECTED_KIND, NULL, _("'%s' is not a file or directory"), - kind1 == svn_node_none ? - local_abspath1 : local_abspath2); + kind1 == svn_node_none + ? svn_dirent_local_style(local_abspath1, + scratch_pool) + : svn_dirent_local_style(local_abspath2, + scratch_pool)); return SVN_NO_ERROR; } diff --git a/subversion/libsvn_client/log.c b/subversion/libsvn_client/log.c index ca3edac..73bd612 100644 --- a/subversion/libsvn_client/log.c +++ b/subversion/libsvn_client/log.c @@ -712,7 +712,17 @@ run_ra_get_log(apr_array_header_t *revision_ranges, matching_segment = bsearch(&younger_rev, log_segments->elts, log_segments->nelts, log_segments->elt_size, compare_rev_to_segment); - SVN_ERR_ASSERT(*matching_segment); + /* LOG_SEGMENTS is supposed to represent the history of PATHS from + the oldest to youngest revs in REVISION_RANGES. This function's + current sole caller svn_client_log5 *should* be providing + LOG_SEGMENTS that span the oldest to youngest revs in + REVISION_RANGES, even if one or more of the svn_location_segment_t's + returned have NULL path members indicating a gap in the history. So + MATCHING_SEGMENT should never be NULL, but clearly sometimes it is, + see http://svn.haxx.se/dev/archive-2013-06/0522.shtml + So to be safe we handle that case. */ + if (matching_segment == NULL) + continue; /* A segment with a NULL path means there is gap in the history. We'll just proceed and let svn_ra_get_log2 fail with a useful @@ -850,13 +860,32 @@ svn_client_log5(const apr_array_header_t *targets, SVN_ERR(svn_client__ensure_ra_session_url(&old_session_url, ra_session, actual_loc->url, pool)); - /* Get the svn_location_segment_t's representing the requested log ranges. */ - SVN_ERR(svn_client__repos_location_segments(&log_segments, ra_session, - actual_loc->url, - actual_loc->rev, /* peg */ - actual_loc->rev, /* start */ - oldest_rev, /* end */ - ctx, pool)); + /* Save us an RA layer round trip if we are on the repository root and + know the result in advance. All the revision data has already been + validated. + */ + if (strcmp(actual_loc->url, actual_loc->repos_root_url) == 0) + { + svn_location_segment_t *segment = apr_pcalloc(pool, sizeof(*segment)); + log_segments = apr_array_make(pool, 1, sizeof(segment)); + + segment->range_start = oldest_rev; + segment->range_end = actual_loc->rev; + segment->path = ""; + APR_ARRAY_PUSH(log_segments, svn_location_segment_t *) = segment; + } + else + { + /* Get the svn_location_segment_t's representing the requested log + * ranges. */ + SVN_ERR(svn_client__repos_location_segments(&log_segments, ra_session, + actual_loc->url, + actual_loc->rev, /* peg */ + actual_loc->rev, /* start */ + oldest_rev, /* end */ + ctx, pool)); + } + SVN_ERR(run_ra_get_log(revision_ranges, relative_targets, log_segments, actual_loc, ra_session, targets, limit, diff --git a/subversion/libsvn_client/merge.c b/subversion/libsvn_client/merge.c index 884d63d..17a5d23 100644 --- a/subversion/libsvn_client/merge.c +++ b/subversion/libsvn_client/merge.c @@ -1307,6 +1307,9 @@ record_tree_conflict(merge_cmd_baton_t *merge_b, { svn_wc_context_t *wc_ctx = merge_b->ctx->wc_ctx; + if (merge_b->record_only) + return SVN_NO_ERROR; + if (merge_b->merge_source.ancestral || merge_b->reintegrate_merge) { @@ -1316,8 +1319,7 @@ record_tree_conflict(merge_cmd_baton_t *merge_b, alloc_and_store_path(&merge_b->conflicted_paths, local_abspath, merge_b->pool); - - if (!merge_b->record_only && !merge_b->dry_run) + if (!merge_b->dry_run) { svn_wc_conflict_description2_t *conflict; const svn_wc_conflict_version_t *left; @@ -12029,16 +12031,17 @@ operative_rev_receiver(void *baton, return svn_error_create(SVN_ERR_CEASE_INVOCATION, NULL, NULL); } -/* Wrapper around svn_client_mergeinfo_log2. All arguments are as per - that API. The discover_changed_paths, depth, and revprops args to - svn_client_mergeinfo_log2 are always TRUE, svn_depth_infinity_t, - and NULL respectively. +/* Wrapper around svn_client__mergeinfo_log. All arguments are as per + that private API. The discover_changed_paths, depth, and revprops args to + svn_client__mergeinfo_log are always TRUE, svn_depth_infinity_t, + and empty array respectively. If RECEIVER raises a SVN_ERR_CEASE_INVOCATION error, but still sets *REVISION to a valid revnum, then clear the error. Otherwise return any error. */ static svn_error_t* -short_circuit_mergeinfo_log(svn_boolean_t finding_merged, +short_circuit_mergeinfo_log(svn_mergeinfo_catalog_t *target_mergeinfo_cat, + svn_boolean_t finding_merged, const char *target_path_or_url, const svn_opt_revision_t *target_peg_revision, const char *source_path_or_url, @@ -12048,18 +12051,25 @@ short_circuit_mergeinfo_log(svn_boolean_t finding_merged, svn_log_entry_receiver_t receiver, svn_revnum_t *revision, svn_client_ctx_t *ctx, + apr_pool_t *result_pool, apr_pool_t *scratch_pool) { - svn_error_t *err = svn_client_mergeinfo_log2(finding_merged, - target_path_or_url, - target_peg_revision, - source_path_or_url, - source_peg_revision, - source_start_revision, - source_end_revision, - receiver, revision, - TRUE, svn_depth_infinity, - NULL, ctx, scratch_pool); + apr_array_header_t *revprops; + svn_error_t *err; + + revprops = apr_array_make(scratch_pool, 0, sizeof(const char *)); + err = svn_client__mergeinfo_log(finding_merged, + target_path_or_url, + target_peg_revision, + target_mergeinfo_cat, + source_path_or_url, + source_peg_revision, + source_start_revision, + source_end_revision, + receiver, revision, + TRUE, svn_depth_infinity, + revprops, ctx, result_pool, + scratch_pool); if (err) { @@ -12129,6 +12139,7 @@ find_last_merged_location(svn_client__pathrev_t **base_p, svn_opt_revision_t source_peg_rev, source_start_rev, source_end_rev, target_opt_rev; svn_revnum_t youngest_merged_rev = SVN_INVALID_REVNUM; + svn_mergeinfo_catalog_t target_mergeinfo_cat = NULL; source_peg_rev.kind = svn_opt_revision_number; source_peg_rev.value.number = source_branch->tip->rev; @@ -12141,14 +12152,15 @@ find_last_merged_location(svn_client__pathrev_t **base_p, /* Find the youngest revision fully merged from SOURCE_BRANCH to TARGET, if such a revision exists. */ - SVN_ERR(short_circuit_mergeinfo_log(TRUE, /* Find merged */ + SVN_ERR(short_circuit_mergeinfo_log(&target_mergeinfo_cat, + TRUE, /* Find merged */ target->url, &target_opt_rev, source_branch->tip->url, &source_peg_rev, &source_end_rev, &source_start_rev, operative_rev_receiver, &youngest_merged_rev, - ctx, scratch_pool)); + ctx, result_pool, scratch_pool)); if (!SVN_IS_VALID_REVNUM(youngest_merged_rev)) { @@ -12175,14 +12187,15 @@ find_last_merged_location(svn_client__pathrev_t **base_p, (i.e. finding the youngest revision after the YCA where all revs have been merged) that doesn't matter. */ source_end_rev.value.number = youngest_merged_rev; - SVN_ERR(short_circuit_mergeinfo_log(FALSE, /* Find eligible */ + SVN_ERR(short_circuit_mergeinfo_log(&target_mergeinfo_cat, + FALSE, /* Find eligible */ target->url, &target_opt_rev, source_branch->tip->url, &source_peg_rev, &source_start_rev, &source_end_rev, operative_rev_receiver, &oldest_eligible_rev, - ctx, scratch_pool)); + ctx, scratch_pool, scratch_pool)); /* If there are revisions eligible for merging, use the oldest one to calculate the base. Otherwise there are no operative revisions @@ -12298,9 +12311,13 @@ find_automatic_merge(svn_client__pathrev_t **base_p, &s_t->target->loc, SVN_INVALID_REVNUM, SVN_INVALID_REVNUM, s_t->target_ra_session, ctx, scratch_pool)); - SVN_ERR(svn_client__get_youngest_common_ancestor( - &s_t->yca, s_t->source, &s_t->target->loc, s_t->source_ra_session, - ctx, result_pool, result_pool)); + SVN_ERR(svn_client__calc_youngest_common_ancestor( + &s_t->yca, s_t->source, s_t->source_branch.history, + s_t->source_branch.has_r0_history, + &s_t->target->loc, s_t->target_branch.history, + s_t->target_branch.has_r0_history, + result_pool, scratch_pool)); + if (! s_t->yca) return svn_error_createf(SVN_ERR_CLIENT_NOT_READY_TO_MERGE, NULL, _("'%s@%ld' must be ancestrally related to " diff --git a/subversion/libsvn_client/mergeinfo.c b/subversion/libsvn_client/mergeinfo.c index 453cc66..6dd3434 100644 --- a/subversion/libsvn_client/mergeinfo.c +++ b/subversion/libsvn_client/mergeinfo.c @@ -1651,11 +1651,11 @@ svn_client_mergeinfo_get_merged(apr_hash_t **mergeinfo_p, return SVN_NO_ERROR; } - svn_error_t * -svn_client_mergeinfo_log2(svn_boolean_t finding_merged, +svn_client__mergeinfo_log(svn_boolean_t finding_merged, const char *target_path_or_url, const svn_opt_revision_t *target_peg_revision, + svn_mergeinfo_catalog_t *target_mergeinfo_catalog, const char *source_path_or_url, const svn_opt_revision_t *source_peg_revision, const svn_opt_revision_t *source_start_revision, @@ -1666,12 +1666,15 @@ svn_client_mergeinfo_log2(svn_boolean_t finding_merged, svn_depth_t depth, const apr_array_header_t *revprops, svn_client_ctx_t *ctx, + apr_pool_t *result_pool, apr_pool_t *scratch_pool) { const char *log_target = NULL; const char *repos_root; const char *target_repos_relpath; svn_mergeinfo_catalog_t target_mergeinfo_cat; + svn_ra_session_t *target_session = NULL; + svn_client__pathrev_t *pathrev; /* A hash of paths, at or under TARGET_PATH_OR_URL, mapped to rangelists. Not technically mergeinfo, so not using the @@ -1688,6 +1691,7 @@ svn_client_mergeinfo_log2(svn_boolean_t finding_merged, apr_hash_index_t *hi; apr_pool_t *iterpool; svn_boolean_t oldest_revs_first = TRUE; + apr_pool_t *subpool; /* We currently only support depth = empty | infinity. */ if (depth != svn_depth_infinity && depth != svn_depth_empty) @@ -1713,6 +1717,8 @@ svn_client_mergeinfo_log2(svn_boolean_t finding_merged, && (source_start_revision->kind != svn_opt_revision_unspecified)) return svn_error_create(SVN_ERR_CLIENT_BAD_REVISION, NULL, NULL); + subpool = svn_pool_create(scratch_pool); + /* We need the union of TARGET_PATH_OR_URL@TARGET_PEG_REVISION's mergeinfo and MERGE_SOURCE_URL's history. It's not enough to do path matching, because renames in the history of MERGE_SOURCE_URL @@ -1720,10 +1726,45 @@ svn_client_mergeinfo_log2(svn_boolean_t finding_merged, the target, that vastly simplifies matters (we'll have nothing to do). */ /* This get_mergeinfo() call doubles as a mergeinfo capabilities check. */ - SVN_ERR(get_mergeinfo(&target_mergeinfo_cat, &repos_root, - target_path_or_url, target_peg_revision, - depth == svn_depth_infinity, TRUE, - ctx, scratch_pool, scratch_pool)); + if (target_mergeinfo_catalog) + { + if (*target_mergeinfo_catalog) + { + /* The caller provided the mergeinfo catalog for + TARGET_PATH_OR_URL, so we don't need to accquire + it ourselves. We do need to get the repos_root + though, because get_mergeinfo() won't do it for us. */ + target_mergeinfo_cat = *target_mergeinfo_catalog; + SVN_ERR(svn_client__ra_session_from_path2(&target_session, &pathrev, + target_path_or_url, NULL, + target_peg_revision, + target_peg_revision, + ctx, subpool)); + SVN_ERR(svn_ra_get_repos_root2(target_session, &repos_root, + scratch_pool)); + } + else + { + /* The caller didn't provide the mergeinfo catalog for + TARGET_PATH_OR_URL, but wants us to pass a copy back + when we get it, so use RESULT_POOL. */ + SVN_ERR(get_mergeinfo(target_mergeinfo_catalog, &repos_root, + target_path_or_url, target_peg_revision, + depth == svn_depth_infinity, TRUE, + ctx, result_pool, scratch_pool)); + target_mergeinfo_cat = *target_mergeinfo_catalog; + } + } + else + { + /* The caller didn't provide the mergeinfo catalog for + TARGET_PATH_OR_URL, nor does it want a copy, so we can use + nothing but SCRATCH_POOL. */ + SVN_ERR(get_mergeinfo(&target_mergeinfo_cat, &repos_root, + target_path_or_url, target_peg_revision, + depth == svn_depth_infinity, TRUE, + ctx, scratch_pool, scratch_pool)); + } if (!svn_path_is_url(target_path_or_url)) { @@ -1755,6 +1796,7 @@ svn_client_mergeinfo_log2(svn_boolean_t finding_merged, history. */ if (finding_merged) { + svn_pool_destroy(subpool); return SVN_NO_ERROR; } else @@ -1772,18 +1814,17 @@ svn_client_mergeinfo_log2(svn_boolean_t finding_merged, * ### TODO: As the source and target must be in the same repository, we * should share a single session, tracking the two URLs separately. */ { - apr_pool_t *sesspool = svn_pool_create(scratch_pool); - svn_ra_session_t *source_session, *target_session; - svn_client__pathrev_t *pathrev; + svn_ra_session_t *source_session; svn_revnum_t start_rev, end_rev, youngest_rev = SVN_INVALID_REVNUM; if (! finding_merged) { - SVN_ERR(svn_client__ra_session_from_path2(&target_session, &pathrev, - target_path_or_url, NULL, - target_peg_revision, - target_peg_revision, - ctx, sesspool)); + if (!target_session) + SVN_ERR(svn_client__ra_session_from_path2(&target_session, &pathrev, + target_path_or_url, NULL, + target_peg_revision, + target_peg_revision, + ctx, subpool)); SVN_ERR(svn_client__get_history_as_mergeinfo(&target_history, NULL, pathrev, SVN_INVALID_REVNUM, @@ -1796,17 +1837,17 @@ svn_client_mergeinfo_log2(svn_boolean_t finding_merged, source_path_or_url, NULL, source_peg_revision, source_peg_revision, - ctx, sesspool)); + ctx, subpool)); SVN_ERR(svn_client__get_revision_number(&start_rev, &youngest_rev, ctx->wc_ctx, source_path_or_url, source_session, source_start_revision, - sesspool)); + subpool)); SVN_ERR(svn_client__get_revision_number(&end_rev, &youngest_rev, ctx->wc_ctx, source_path_or_url, source_session, source_end_revision, - sesspool)); + subpool)); SVN_ERR(svn_client__get_history_as_mergeinfo(&source_history, NULL, pathrev, MAX(end_rev, start_rev), @@ -1817,7 +1858,7 @@ svn_client_mergeinfo_log2(svn_boolean_t finding_merged, oldest_revs_first = FALSE; /* Close the source and target sessions. */ - svn_pool_destroy(sesspool); + svn_pool_destroy(subpool); } /* Separate the explicit or inherited mergeinfo on TARGET_PATH_OR_URL, @@ -2090,6 +2131,31 @@ svn_client_mergeinfo_log2(svn_boolean_t finding_merged, } svn_error_t * +svn_client_mergeinfo_log2(svn_boolean_t finding_merged, + const char *target_path_or_url, + const svn_opt_revision_t *target_peg_revision, + const char *source_path_or_url, + const svn_opt_revision_t *source_peg_revision, + const svn_opt_revision_t *source_start_revision, + const svn_opt_revision_t *source_end_revision, + svn_log_entry_receiver_t log_receiver, + void *log_receiver_baton, + svn_boolean_t discover_changed_paths, + svn_depth_t depth, + const apr_array_header_t *revprops, + svn_client_ctx_t *ctx, + apr_pool_t *scratch_pool) +{ + return svn_client__mergeinfo_log(finding_merged, target_path_or_url, + target_peg_revision, NULL, + source_path_or_url, source_peg_revision, + source_start_revision, source_end_revision, + log_receiver, log_receiver_baton, + discover_changed_paths, depth, revprops, + ctx, scratch_pool, scratch_pool); +} + +svn_error_t * svn_client_suggest_merge_sources(apr_array_header_t **suggestions, const char *path_or_url, const svn_opt_revision_t *peg_revision, diff --git a/subversion/libsvn_client/ra.c b/subversion/libsvn_client/ra.c index 33d3de5..a0d4cea 100644 --- a/subversion/libsvn_client/ra.c +++ b/subversion/libsvn_client/ra.c @@ -862,23 +862,20 @@ svn_client__repos_locations(const char **start_url, return SVN_NO_ERROR; } - svn_error_t * -svn_client__get_youngest_common_ancestor(svn_client__pathrev_t **ancestor_p, - const svn_client__pathrev_t *loc1, - const svn_client__pathrev_t *loc2, - svn_ra_session_t *session, - svn_client_ctx_t *ctx, - apr_pool_t *result_pool, - apr_pool_t *scratch_pool) +svn_client__calc_youngest_common_ancestor(svn_client__pathrev_t **ancestor_p, + const svn_client__pathrev_t *loc1, + apr_hash_t *history1, + svn_boolean_t has_rev_zero_history1, + const svn_client__pathrev_t *loc2, + apr_hash_t *history2, + svn_boolean_t has_rev_zero_history2, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool) { - apr_pool_t *sesspool = NULL; - apr_hash_t *history1, *history2; apr_hash_index_t *hi; svn_revnum_t yc_revision = SVN_INVALID_REVNUM; const char *yc_relpath = NULL; - svn_boolean_t has_rev_zero_history1; - svn_boolean_t has_rev_zero_history2; if (strcmp(loc1->repos_root_url, loc2->repos_root_url) != 0) { @@ -886,32 +883,6 @@ svn_client__get_youngest_common_ancestor(svn_client__pathrev_t **ancestor_p, return SVN_NO_ERROR; } - /* Open an RA session for the two locations. */ - if (session == NULL) - { - sesspool = svn_pool_create(scratch_pool); - SVN_ERR(svn_client_open_ra_session2(&session, loc1->url, NULL, ctx, - sesspool, sesspool)); - } - - /* We're going to cheat and use history-as-mergeinfo because it - saves us a bunch of annoying custom data comparisons and such. */ - SVN_ERR(svn_client__get_history_as_mergeinfo(&history1, - &has_rev_zero_history1, - loc1, - SVN_INVALID_REVNUM, - SVN_INVALID_REVNUM, - session, ctx, scratch_pool)); - SVN_ERR(svn_client__get_history_as_mergeinfo(&history2, - &has_rev_zero_history2, - loc2, - SVN_INVALID_REVNUM, - SVN_INVALID_REVNUM, - session, ctx, scratch_pool)); - /* Close the ra session if we opened one. */ - if (sesspool) - svn_pool_destroy(sesspool); - /* Loop through the first location's history, check for overlapping paths and ranges in the second location's history, and remembering the youngest matching location. */ @@ -965,6 +936,63 @@ svn_client__get_youngest_common_ancestor(svn_client__pathrev_t **ancestor_p, } svn_error_t * +svn_client__get_youngest_common_ancestor(svn_client__pathrev_t **ancestor_p, + const svn_client__pathrev_t *loc1, + const svn_client__pathrev_t *loc2, + svn_ra_session_t *session, + svn_client_ctx_t *ctx, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool) +{ + apr_pool_t *sesspool = NULL; + apr_hash_t *history1, *history2; + svn_boolean_t has_rev_zero_history1; + svn_boolean_t has_rev_zero_history2; + + if (strcmp(loc1->repos_root_url, loc2->repos_root_url) != 0) + { + *ancestor_p = NULL; + return SVN_NO_ERROR; + } + + /* Open an RA session for the two locations. */ + if (session == NULL) + { + sesspool = svn_pool_create(scratch_pool); + SVN_ERR(svn_client_open_ra_session2(&session, loc1->url, NULL, ctx, + sesspool, sesspool)); + } + + /* We're going to cheat and use history-as-mergeinfo because it + saves us a bunch of annoying custom data comparisons and such. */ + SVN_ERR(svn_client__get_history_as_mergeinfo(&history1, + &has_rev_zero_history1, + loc1, + SVN_INVALID_REVNUM, + SVN_INVALID_REVNUM, + session, ctx, scratch_pool)); + SVN_ERR(svn_client__get_history_as_mergeinfo(&history2, + &has_rev_zero_history2, + loc2, + SVN_INVALID_REVNUM, + SVN_INVALID_REVNUM, + session, ctx, scratch_pool)); + /* Close the ra session if we opened one. */ + if (sesspool) + svn_pool_destroy(sesspool); + + SVN_ERR(svn_client__calc_youngest_common_ancestor(ancestor_p, + loc1, history1, + has_rev_zero_history1, + loc2, history2, + has_rev_zero_history2, + result_pool, + scratch_pool)); + + return SVN_NO_ERROR; +} + +svn_error_t * svn_client__youngest_common_ancestor(const char **ancestor_url, svn_revnum_t *ancestor_rev, const char *path_or_url1, diff --git a/subversion/libsvn_client/switch.c b/subversion/libsvn_client/switch.c index fae03de..cd39cad 100644 --- a/subversion/libsvn_client/switch.c +++ b/subversion/libsvn_client/switch.c @@ -241,7 +241,7 @@ switch_internal(svn_revnum_t *result_rev, return svn_error_createf(SVN_ERR_CLIENT_UNRELATED_RESOURCES, NULL, _("'%s' shares no common ancestry with '%s'"), switch_url, - svn_dirent_dirname(local_abspath, pool)); + svn_dirent_local_style(local_abspath, pool)); } wcroot_iprops = apr_hash_make(pool); |