Index: subversion/include/svn_client.h
===================================================================
--- subversion/include/svn_client.h (revision 30369)
+++ subversion/include/svn_client.h (working copy)
@@ -2660,6 +2660,32 @@
apr_pool_t *pool);
/**
+ * Set @a *mergeinfo to a hash mapping const char * merge
+ * source URLs to apr_array_header_t * rangelists (arrays of
+ * svn_merge_range_t * ranges)o describing the ranges which
+ * have been merged into @a path_or_url as of @a peg_revision, or @c
+ * NULL if there is no mergeinfo.
+ *
+ * Use @a pool for all necessary allocations.
+ *
+ * If the server doesn't support retrieval of mergeinfo (which will
+ * never happen for file:// URLs), return an @c
+ * SVN_ERR_UNSUPPORTED_FEATURE error.
+ *
+ * @note Unlike most APIs which deal with mergeinfo, this one returns
+ * data where the keys of the hash are absolute repository URLs rather
+ * than repository filesystem paths.
+ *
+ * @since New in 1.5.
+ */
+svn_error_t *
+svn_client_mergeinfo_get_merged(apr_hash_t **mergeinfo,
+ const char *path_or_url,
+ const svn_opt_revision_t *peg_revision,
+ svn_client_ctx_t *ctx,
+ apr_pool_t *pool);
+
+/**
* Drive log entry callbacks @a receiver / @a receiver_baton with the
* revisions eligible for merge from @a merge_source_url (as of @a
* src_peg_revision) into @a path_or_url (as of @a peg_revision). @a
@@ -2685,6 +2711,30 @@
svn_client_ctx_t *ctx,
apr_pool_t *pool);
+/**
+ * Set @a *rangelist to a list of svn_merge_range_t *
+ * items representing eligible ranges of revisions which have not yet
+ * been merged from @a merge_source_url into @a path_or_url as of @a
+ * peg_revision, or @c NULL if all candidate revisions of @a
+ * merge_source_url have already been merged.
+ *
+ * Use @a pool for all necessary allocations.
+ *
+ * If the server doesn't support retrieval of mergeinfo (which will
+ * never happen for file:// URLs), return an @c
+ * SVN_ERR_UNSUPPORTED_FEATURE error.
+ *
+ * @since New in 1.5.
+ */
+svn_error_t *
+svn_client_mergeinfo_get_eligible(apr_array_header_t **rangelist,
+ const char *path_or_url,
+ const svn_opt_revision_t *peg_revision,
+ const char *merge_source_url,
+ const svn_opt_revision_t *src_peg_revision,
+ svn_client_ctx_t *ctx,
+ apr_pool_t *pool);
+
/** @} */
/**
Index: subversion/libsvn_client/mergeinfo.c
===================================================================
--- subversion/libsvn_client/mergeinfo.c (revision 30369)
+++ subversion/libsvn_client/mergeinfo.c (working copy)
@@ -1207,6 +1207,47 @@
svn_error_t *
+svn_client_mergeinfo_get_merged(apr_hash_t **mergeinfo_p,
+ const char *path_or_url,
+ const svn_opt_revision_t *peg_revision,
+ svn_client_ctx_t *ctx,
+ apr_pool_t *pool)
+{
+ const char *repos_root;
+ apr_hash_t *full_path_mergeinfo;
+ svn_mergeinfo_t mergeinfo;
+
+ SVN_ERR(get_mergeinfo(&mergeinfo, &repos_root, path_or_url,
+ peg_revision, ctx, pool));
+
+ /* Copy the MERGEINFO hash items into another hash, but change
+ the relative paths into full URLs. */
+ *mergeinfo_p = NULL;
+ if (mergeinfo)
+ {
+ apr_hash_index_t *hi;
+
+ full_path_mergeinfo = apr_hash_make(pool);
+ for (hi = apr_hash_first(pool, mergeinfo); hi; hi = apr_hash_next(hi))
+ {
+ const void *key;
+ void *val;
+ const char *source_url;
+
+ apr_hash_this(hi, &key, NULL, &val);
+ source_url = svn_path_uri_encode(key, pool);
+ source_url = svn_path_join(repos_root, source_url + 1, pool);
+ apr_hash_set(full_path_mergeinfo, source_url,
+ APR_HASH_KEY_STRING, val);
+ }
+ *mergeinfo_p = full_path_mergeinfo;
+ }
+
+ return SVN_NO_ERROR;
+}
+
+
+svn_error_t *
svn_client_mergeinfo_log_eligible(const char *path_or_url,
const svn_opt_revision_t *peg_revision,
const char *merge_source_url,
@@ -1308,6 +1349,77 @@
svn_error_t *
+svn_client_mergeinfo_get_eligible(apr_array_header_t **rangelist,
+ const char *path_or_url,
+ const svn_opt_revision_t *peg_revision,
+ const char *merge_source_url,
+ const svn_opt_revision_t *src_peg_revision,
+ svn_client_ctx_t *ctx,
+ apr_pool_t *pool)
+{
+ svn_mergeinfo_t mergeinfo, history, source_history, available;
+ apr_hash_index_t *hi;
+ svn_ra_session_t *ra_session;
+ int num_ranges = 0;
+ const char *repos_root;
+ apr_pool_t *sesspool;
+
+ assert(svn_path_is_url(merge_source_url));
+
+ /* Step 1: Across the set of possible merges, see what's already
+ been merged into PATH_OR_URL@PEG_REVISION (or what's already part
+ of the history it shares with that of MERGE_SOURCE_URL. */
+ SVN_ERR(get_mergeinfo(&mergeinfo, &repos_root, path_or_url,
+ peg_revision, ctx, pool));
+ SVN_ERR(svn_client__get_history_as_mergeinfo(&history,
+ path_or_url,
+ peg_revision,
+ SVN_INVALID_REVNUM,
+ SVN_INVALID_REVNUM,
+ NULL, NULL, ctx, pool));
+ if (! mergeinfo)
+ mergeinfo = history;
+ else
+ svn_mergeinfo_merge(mergeinfo, history, pool);
+
+ /* Step 2: See what merge sources can be derived from the history of
+ MERGE_SOURCE_URL. */
+ sesspool = svn_pool_create(pool);
+ SVN_ERR(svn_client__open_ra_session_internal(&ra_session, merge_source_url,
+ NULL, NULL, NULL, FALSE,
+ TRUE, ctx, sesspool));
+ SVN_ERR(svn_client__get_history_as_mergeinfo(&source_history,
+ merge_source_url,
+ src_peg_revision,
+ SVN_INVALID_REVNUM,
+ SVN_INVALID_REVNUM,
+ ra_session, NULL, ctx, pool));
+ svn_pool_destroy(sesspool);
+
+ /* Now, we want to remove from the possible mergeinfo
+ (SOURCE_HISTORY) the merges already present in our PATH_OR_URL. */
+ SVN_ERR(svn_mergeinfo_remove(&available, mergeinfo, source_history, pool));
+
+ /* Finally, we want to provide a simple, single revision range list
+ to our caller. Now, interestingly, if MERGE_SOURCE_URL has been
+ renamed over time, there's good chance that set of available
+ merges have different paths assigned to them. Fortunately, we
+ know that we can't have any two paths in AVAILABLE with
+ overlapping revisions (because the original SOURCE_HISTORY also
+ had this property). So we'll just collapse into one rangelist
+ all the rangelists across all the paths in AVAILABLE. */
+ *rangelist = apr_array_make(pool, num_ranges, sizeof(svn_merge_range_t *));
+ for (hi = apr_hash_first(pool, available); hi; hi = apr_hash_next(hi))
+ {
+ void *val;
+ apr_hash_this(hi, NULL, NULL, &val);
+ SVN_ERR(svn_rangelist_merge(rangelist, val, pool));
+ }
+ return SVN_NO_ERROR;
+}
+
+
+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,