On Nov 22, 2007 11:35 AM, <kameshj@tigris.org> wrote:
> Author: kameshj
> Date: Thu Nov 22 11:35:07 2007
> New Revision: 27982
>
> Log:
> On issue-2897 branch: Fix 2897 Reflective merges are faulty.
>
> Fix invloves 3 changes.
> - Schema change to track what revisions of merge source got merged in a
> given commit in 'mergeinfo_changed' table.
> - implement 'get_commit_revs_for_merge_ranges' API to get the commit revs
> for the reflective merge.
> - negate the reflective revision from the requested merge range.
>
> * subversion/libsvn_fs_util/sqlite-util.c
> (schema_create_sql): Make the following change to the schema of
> 'mergeinfo_changed' table.
> Rename column 'path' -> 'mergedto'
> New column 'mergedfrom' to track the 'merge source canonical path'.
> New columns 'mergedrevstart', 'mergedrevend' and 'inheritable' to track
> the merge revision range for this commit.
> Drop the indices mi_c_revpath_idx, mi_c_path_idx, mi_c_revision_idx.
> New index 'mi_c_merge_source_target_revstart_end_commit_rev_idx'.
> * subversion/libsvn_fs_util/mergeinfo-sqlite-index.c
> (): include svn_sorts.h
> (get_mergeinfo): Forward declaration, so that 'index_txn_mergeinfo' can also
> make use of this function.
> (index_path_mergeinfo): Change signature to accept hashes 'curr_mergeinfo',
> 'orig_mergeinfo', 'added_mergeinfo' instead of 'mergeinfo_str'(which is a
> mergeinfo as at this commit). Record full details about the merge for the
> given commit in 'mergeinfo_changed' table.
> (index_txn_mergeinfo): Call 'index_path_mergeinfo' with necessary arguments
> as per new signature.
> (get_mergeinfo_for_path, get_mergeinfo_for_children): Adjust the query for
> the new schema change.
> (get_parent_target_path_having_mergeinfo,
> get_commit_revs_for_merge_ranges,
> svn_fs_mergeinfo__get_commit_revs_for_merge_ranges): New function.
>
> * subversion/include/private/svn_fs_mergeinfo.h
> (): Prototype 'svn_fs_mergeinfo__get_commit_revs_for_merge_ranges'.
>
> * subversion/libsvn_fs/fs-loader.h
> (root_vtable_t): Introduce new member 'get_commit_revs_for_merge_ranges'.
>
> * subversion/libsvn_fs_base/tree.c
> subversion/libsvn_fs_fs/tree.c
> (root_vtable): Use 'svn_fs_mergeinfo__get_commit_revs_for_merge_ranges' as
> the above new member to root_vtable_t.
>
> * subversion/libsvn_fs/fs-loader.c
> (svn_fs_get_commit_revs_for_merge_ranges): Implement FS stub of this new
> functionality.
> * subversion/include/svn_fs.h
> (): Prototype svn_fs_get_commit_revs_for_merge_ranges.
>
> * subversion/libsvn_repos/fs-wrap.c
> (svn_repos_get_commit_revs_for_merge_ranges): Implement REPOS stub of this
> new functionality.
>
> * subversion/include/svn_repos.h
> (): Prototype svn_repos_get_commit_revs_for_merge_ranges.
>
> * subversion/include/private/svn_dav_protocol.h
> (SVN_DAV__COMMIT_REVS_FOR_MERGE_RANGES_REPORT,
> SVN_DAV__MAX_COMMIT_REVISION,
> SVN_DAV__MIN_COMMIT_REVISION,
> SVN_DAV__MERGE_SOURCE,
> SVN_DAV__MERGE_TARGET,
> SVN_DAV__MERGE_RANGES): New Macro.
>
> * subversion/mod_dav_svn/dav_svn.h
> (): Prototype dav_svn__get_commit_revs_for_merge_ranges_report.
>
> * subversion/mod_dav_svn/reports/mergeinfo.c
> (): include svn_mergeinfo.h.
> (dav_svn__get_commit_revs_for_merge_ranges_report): New function, that
> stubs the MOD_DAV_SVN part of this functionality.
>
> * subversion/mod_dav_svn/version.c
> (deliver_report): Invokes this new functionality
> 'dav_svn__get_commit_revs_for_merge_ranges_report' via the DAV report.
>
> * subversion/svnserve/serve.c
> (main_commands): Add new report 'commit-revs-for-merge-ranges'.
> (get_commit_revs_for_merge_ranges): Implementation of new report.
>
> * subversion/libsvn_ra/ra_loader.h
> (svn_ra__vtable_t): Add new member 'get_commit_revs_for_merge_ranges'
> for ra_layers to define relevant functions to.
>
> * subversion/libsvn_ra_local/ra_plugin.c
> (svn_ra_local__get_commit_revs_for_merge_ranges): Implement ra_local plugin
> for this new functionality.
> (ra_local_vtable): Set the new member with
> svn_ra_local__get_commit_revs_for_merge_ranges.
>
> * subversion/libsvn_ra_svn/client.c
> (ra_svn_get_commit_revs_for_merge_ranges): Implement ra_svn plugin
> for this new functionality.
> (ra_svn_vtable): Set the new member with
> ra_svn_get_commit_revs_for_merge_ranges.
>
> * subversion/libsvn_ra_neon/ra_neon.h
> (): Prototype 'svn_ra_neon__get_commit_revs_for_merge_ranges'.
>
> * subversion/libsvn_ra_neon/mergeinfo.c
> (mergeinfo_report_elements): Make mergeinfo parser aware of new report.
> (svn_ra_neon__get_commit_revs_for_merge_ranges): New function.
>
> * subversion/libsvn_ra_neon/session.c
> (neon_vtable): Set the new member with
> 'svn_ra_neon__get_commit_revs_for_merge_ranges'.
>
> * subversion/libsvn_ra_serf/ra_serf.h
> (): Prototype svn_ra_serf__get_commit_revs_for_merge_ranges.
>
> * subversion/libsvn_ra_serf/mergeinfo.c
> (mergeinfo_context_t): Add member 'merge_target', 'merge_source'
> 'min_commit_rev', 'max_commit_rev', 'merge_rangelist_str'.
> (start_element, end_element): Make the parser knowledegable about
> new commit-revs report.
> (create_commit_revs_for_merge_ranges_body): New function.
> (svn_ra_serf__get_commit_revs_for_merge_ranges): New function.
>
> * subversion/libsvn_ra_serf/serf.c
> (serf_vtable): Set the new member with
> 'svn_ra_serf__get_commit_revs_for_merge_ranges'.
>
> * subversion/include/svn_ra.h
> (): Prototype svn_ra_get_commit_revs_for_merge_ranges.
>
> * subversion/libsvn_ra/ra_loader.c
> (svn_ra_get_commit_revs_for_merge_ranges): New function.
>
> * subversion/tests/cmdline/merge_tests.py
> (test_list): Remove XFail marker from 'avoid_reflected_revs'.
>
> * subversion/libsvn_client/merge.c
> (filter_reflected_revisions): Get the reflected revision range and remove
> it from the requested merge range.
>
>
> Modified:
> branches/issue-2897/subversion/include/private/svn_dav_protocol.h
> branches/issue-2897/subversion/include/private/svn_fs_mergeinfo.h
> branches/issue-2897/subversion/include/svn_fs.h
> branches/issue-2897/subversion/include/svn_ra.h
> branches/issue-2897/subversion/include/svn_repos.h
> branches/issue-2897/subversion/libsvn_client/merge.c
> branches/issue-2897/subversion/libsvn_fs/fs-loader.c
> branches/issue-2897/subversion/libsvn_fs/fs-loader.h
> branches/issue-2897/subversion/libsvn_fs_base/tree.c
> branches/issue-2897/subversion/libsvn_fs_fs/tree.c
> branches/issue-2897/subversion/libsvn_fs_util/mergeinfo-sqlite-index.c
> branches/issue-2897/subversion/libsvn_fs_util/sqlite-util.c
> branches/issue-2897/subversion/libsvn_ra/ra_loader.c
> branches/issue-2897/subversion/libsvn_ra/ra_loader.h
> branches/issue-2897/subversion/libsvn_ra_local/ra_plugin.c
> branches/issue-2897/subversion/libsvn_ra_neon/mergeinfo.c
> branches/issue-2897/subversion/libsvn_ra_neon/ra_neon.h
> branches/issue-2897/subversion/libsvn_ra_neon/session.c
> branches/issue-2897/subversion/libsvn_ra_serf/mergeinfo.c
> branches/issue-2897/subversion/libsvn_ra_serf/ra_serf.h
> branches/issue-2897/subversion/libsvn_ra_serf/serf.c
> branches/issue-2897/subversion/libsvn_ra_svn/client.c
> branches/issue-2897/subversion/libsvn_repos/fs-wrap.c
> branches/issue-2897/subversion/mod_dav_svn/dav_svn.h
> branches/issue-2897/subversion/mod_dav_svn/reports/mergeinfo.c
> branches/issue-2897/subversion/mod_dav_svn/version.c
> branches/issue-2897/subversion/svnserve/serve.c
> branches/issue-2897/subversion/tests/cmdline/merge_tests.py
>
> Modified: branches/issue-2897/subversion/include/private/svn_dav_protocol.h
> URL: http://svn.collab.net/viewvc/svn/branches/issue-2897/subversion/include/private/svn_dav_protocol.h?pathrev=27982&r1=27981&r2=27982
> ==============================================================================
> --- branches/issue-2897/subversion/include/private/svn_dav_protocol.h (original)
> +++ branches/issue-2897/subversion/include/private/svn_dav_protocol.h Thu Nov 22 11:35:07 2007
> @@ -28,6 +28,8 @@
> /** Names for the custom HTTP REPORTs understood by mod_dav_svn, sans
> namespace. */
> #define SVN_DAV__MERGEINFO_REPORT "mergeinfo-report"
> +#define SVN_DAV__COMMIT_REVS_FOR_MERGE_RANGES_REPORT \
> + "commit-revs-for-merge-ranges-report"
>
> /** Names for XML child elements of the custom HTTP REPORTs understood
> by mod_dav_svn, sans namespace. */
> @@ -38,6 +40,11 @@
> #define SVN_DAV__PATH "path"
> #define SVN_DAV__INHERIT "inherit"
> #define SVN_DAV__REVISION "revision"
> +#define SVN_DAV__MAX_COMMIT_REVISION "max-commit-revision"
> +#define SVN_DAV__MIN_COMMIT_REVISION "min-commit-revision"
> +#define SVN_DAV__MERGE_SOURCE "merge-source"
> +#define SVN_DAV__MERGE_TARGET "merge-target"
> +#define SVN_DAV__MERGE_RANGES "merge-ranges"
> #define SVN_DAV__VERSION_NAME "version-name"
>
> #ifdef __cplusplus
>
> Modified: branches/issue-2897/subversion/include/private/svn_fs_mergeinfo.h
> URL: http://svn.collab.net/viewvc/svn/branches/issue-2897/subversion/include/private/svn_fs_mergeinfo.h?pathrev=27982&r1=27981&r2=27982
> ==============================================================================
> --- branches/issue-2897/subversion/include/private/svn_fs_mergeinfo.h (original)
> +++ branches/issue-2897/subversion/include/private/svn_fs_mergeinfo.h Thu Nov 22 11:35:07 2007
> @@ -74,6 +74,32 @@
> void *filter_func_baton,
> apr_pool_t *pool);
>
> +/** Retrieve @a commit_rev_rangelist for a @a merge_rangelist from a given
> + * @a merge_source to a @a merge_target
> + * where each commit_rev in @a commit_rev_rangelist > @a min_commit_rev and
> + * <= @a max_commit_rev.
> +
> + * @a commit_rev_list will never be @c NULL, but may be empty.
> + *
> + * @a root indicates the revision root to use when looking up paths.
> + *
> + * @a inherit indicates whether explicit, explicit or inherited, or
> + * only inherited mergeinfo for @a paths is retrieved.
> + *
> + * Do any necessary temporary allocation in @a pool.
> + */
> +svn_error_t *
> +svn_fs_mergeinfo__get_commit_revs_for_merge_ranges(
> + apr_array_header_t **commit_rev_list,
> + svn_fs_root_t *root,
> + const char* merge_target,
> + const char* merge_source,
> + svn_revnum_t min_commit_rev,
> + svn_revnum_t max_commit_rev,
> + const apr_array_header_t *merge_rangelist,
> + svn_mergeinfo_inheritance_t inherit,
> + apr_pool_t *pool);
> +
> #ifdef __cplusplus
> }
> #endif /* __cplusplus */
>
> Modified: branches/issue-2897/subversion/include/svn_fs.h
> URL: http://svn.collab.net/viewvc/svn/branches/issue-2897/subversion/include/svn_fs.h?pathrev=27982&r1=27981&r2=27982
> ==============================================================================
> --- branches/issue-2897/subversion/include/svn_fs.h (original)
> +++ branches/issue-2897/subversion/include/svn_fs.h Thu Nov 22 11:35:07 2007
> @@ -1261,6 +1261,34 @@
> svn_mergeinfo_inheritance_t inherit,
> apr_pool_t *pool);
>
> +/** Retrieve @a commit_rev_rangelist for a @a merge_rangelist from a given
> + * @a merge_source to a @a merge_target
> + * where each commit_rev in @a commit_rev_rangelist > @a min_commit_rev and
> + * <= @a max_commit_rev.
> + *
> + * @a commit_rev_rangelist will never be @c NULL, but may be empty.
> + *
> + * @a root indicates the revision root to use when looking up paths.
> + *
> + * @a inherit indicates whether explicit, explicit or inherited, or
> + * only inherited mergeinfo for @a paths is retrieved.
> + *
> + * Do any necessary temporary allocation in @a pool.
> + *
> + * @since New in 1.5.
> + */
> +svn_error_t *
> +svn_fs_get_commit_revs_for_merge_ranges(
> + apr_array_header_t **commit_rev_rangelist,
> + svn_fs_root_t *root,
> + const char* merge_target,
> + const char* merge_source,
> + svn_revnum_t min_commit_rev,
> + svn_revnum_t max_commit_rev,
> + const apr_array_header_t *merge_rangelist,
> + svn_mergeinfo_inheritance_t inherit,
> + apr_pool_t *pool);
> +
> /**
> * Optionally filter paths which are discoved to have mergeinfo.
> *
>
> Modified: branches/issue-2897/subversion/include/svn_ra.h
> URL: http://svn.collab.net/viewvc/svn/branches/issue-2897/subversion/include/svn_ra.h?pathrev=27982&r1=27981&r2=27982
> ==============================================================================
> --- branches/issue-2897/subversion/include/svn_ra.h (original)
> +++ branches/issue-2897/subversion/include/svn_ra.h Thu Nov 22 11:35:07 2007
> @@ -863,6 +863,35 @@
> svn_mergeinfo_inheritance_t inherit,
> apr_pool_t *pool);
>
> +/** Retrieve @a commit_rev_rangelist for a @a merge_rangelist from a given
> + * @a merge_source to a @a merge_target
> + * where each commit_rev in @a commit_rev_rangelist > @a min_commit_rev and
> + * <= @a max_commit_rev.
> + *
> + * @a commit_rev_rangelist will never be @c NULL, but may be empty.
> + *
> + * @a session indicates the ra_session of the repository root.
> + *
> + * @a inherit indicates whether explicit, explicit or inherited, or
> + * only inherited mergeinfo for @a paths is retrieved.
> + *
> + * Do any necessary temporary allocation in @a pool.
> + *
> + * @since New in 1.5.
> + */
> +svn_error_t *
> +svn_ra_get_commit_revs_for_merge_ranges(
> + svn_ra_session_t *session,
> + apr_array_header_t **commit_rev_rangelist,
> + const char* merge_target,
> + const char* merge_source,
> + svn_revnum_t min_commit_rev,
> + svn_revnum_t max_commit_rev,
> + const apr_array_header_t *merge_rangelist,
> + svn_mergeinfo_inheritance_t inherit,
> + apr_pool_t *pool);
> +
> +
> /**
> * Ask the RA layer to update a working copy.
> *
>
> Modified: branches/issue-2897/subversion/include/svn_repos.h
> URL: http://svn.collab.net/viewvc/svn/branches/issue-2897/subversion/include/svn_repos.h?pathrev=27982&r1=27981&r2=27982
> ==============================================================================
> --- branches/issue-2897/subversion/include/svn_repos.h (original)
> +++ branches/issue-2897/subversion/include/svn_repos.h Thu Nov 22 11:35:07 2007
> @@ -1321,6 +1321,37 @@
> void *authz_read_baton,
> apr_pool_t *pool);
>
> +/** Retrieve @a commit_rev_rangelist for a @a merge_rangelist from a given
> + * @a merge_source to a @a merge_target
> + * where each commit_rev in @a commit_rev_rangelist > @a min_commit_rev and
> + * <= @a max_commit_rev.
> + *
> + * @a commit_rev_rangelist will never be @c NULL, but may be empty.
> + *
> + * @a inherit indicates whether explicit, explicit or inherited, or
> + * only inherited mergeinfo for @a merge_target is retrieved.
> + *
> + * If optional @a authz_read_func is non-NULL, then use this function
> + * (along with optional @a authz_read_baton) to check the readability
> + * of @a merge_target on which mergeinfo was requested for.
> + *
> + * Do any necessary temporary allocation in @a pool.
> + *
> + * @since New in 1.5.
> + */
> +svn_error_t *
> +svn_repos_get_commit_revs_for_merge_ranges(
> + apr_array_header_t **commit_rev_range_list,
> + svn_repos_t *repos,
> + const char* merge_target,
> + const char* merge_source,
> + svn_revnum_t min_commit_rev,
> + svn_revnum_t max_commit_rev,
> + const apr_array_header_t *merge_rangelist,
> + svn_mergeinfo_inheritance_t inherit,
> + svn_repos_authz_func_t authz_read_func,
> + void *authz_read_baton,
> + apr_pool_t *pool);
>
> /* ---------------------------------------------------------------*/
>
>
> Modified: branches/issue-2897/subversion/libsvn_client/merge.c
> URL: http://svn.collab.net/viewvc/svn/branches/issue-2897/subversion/libsvn_client/merge.c?pathrev=27982&r1=27981&r2=27982
> ==============================================================================
> --- branches/issue-2897/subversion/libsvn_client/merge.c (original)
> +++ branches/issue-2897/subversion/libsvn_client/merge.c Thu Nov 22 11:35:07 2007
> @@ -1227,7 +1227,7 @@
> svn_client_ctx_t *ctx,
> apr_pool_t *pool)
> {
> - apr_array_header_t *src_rangelist_for_tgt = NULL;
> + apr_array_header_t *reflected_rangelist_for_tgt = NULL;
> apr_hash_t *added_mergeinfo, *deleted_mergeinfo,
> *start_mergeinfo, *end_mergeinfo;
> svn_merge_range_t *range = apr_pcalloc(pool, sizeof(*range));
> @@ -1260,11 +1260,20 @@
> if (added_mergeinfo)
> {
> const char *mergeinfo_path;
> + apr_array_header_t *src_rangelist_for_tgt = NULL;
> SVN_ERR(svn_client__path_relative_to_root(&mergeinfo_path, target_url,
> source_root_url, TRUE,
> ra_session, NULL, pool));
> src_rangelist_for_tgt = apr_hash_get(added_mergeinfo, mergeinfo_path,
> APR_HASH_KEY_STRING);
> + if (src_rangelist_for_tgt && src_rangelist_for_tgt->nelts)
> + SVN_ERR(svn_ra_get_commit_revs_for_merge_ranges(ra_session,
> + &reflected_rangelist_for_tgt,
> + max_rel_path, mergeinfo_path,
> + min_rev, max_rev,
> + src_rangelist_for_tgt,
> + svn_mergeinfo_inherited,
> + pool));
> }
>
> /* Create a single-item list of ranges with our one requested range
> @@ -1274,10 +1283,10 @@
> range->end = revision2;
> range->inheritable = inheritable;
> APR_ARRAY_PUSH(*requested_rangelist, svn_merge_range_t *) = range;
> - if (src_rangelist_for_tgt)
> - SVN_ERR(svn_rangelist_remove(requested_rangelist, src_rangelist_for_tgt,
> - *requested_rangelist,
> - FALSE, pool));
> + if (reflected_rangelist_for_tgt)
> + SVN_ERR(svn_rangelist_remove(requested_rangelist,
> + reflected_rangelist_for_tgt,
> + *requested_rangelist, FALSE, pool));
> return SVN_NO_ERROR;
> }
>
>
> Modified: branches/issue-2897/subversion/libsvn_fs/fs-loader.c
> URL: http://svn.collab.net/viewvc/svn/branches/issue-2897/subversion/libsvn_fs/fs-loader.c?pathrev=27982&r1=27981&r2=27982
> ==============================================================================
> --- branches/issue-2897/subversion/libsvn_fs/fs-loader.c (original)
> +++ branches/issue-2897/subversion/libsvn_fs/fs-loader.c Thu Nov 22 11:35:07 2007
> @@ -832,6 +832,29 @@
> }
>
> svn_error_t *
> +svn_fs_get_commit_revs_for_merge_ranges(
> + apr_array_header_t **commit_rev_range_list,
> + svn_fs_root_t *root,
> + const char* merge_target,
> + const char* merge_source,
> + svn_revnum_t min_commit_rev,
> + svn_revnum_t max_commit_rev,
> + const apr_array_header_t *merge_rangelist,
> + svn_mergeinfo_inheritance_t inherit,
> + apr_pool_t *pool)
> +{
> + return root->vtable->get_commit_revs_for_merge_ranges(commit_rev_range_list,
> + root,
> + merge_target,
> + merge_source,
> + min_commit_rev,
> + max_commit_rev,
> + merge_rangelist,
> + inherit,
> + pool);
> +}
> +
> +svn_error_t *
> svn_fs_get_mergeinfo_for_tree(apr_hash_t **mergeinfo,
> svn_fs_root_t *root,
> const apr_array_header_t *paths,
>
> Modified: branches/issue-2897/subversion/libsvn_fs/fs-loader.h
> URL: http://svn.collab.net/viewvc/svn/branches/issue-2897/subversion/libsvn_fs/fs-loader.h?pathrev=27982&r1=27981&r2=27982
> ==============================================================================
> --- branches/issue-2897/subversion/libsvn_fs/fs-loader.h (original)
> +++ branches/issue-2897/subversion/libsvn_fs/fs-loader.h Thu Nov 22 11:35:07 2007
> @@ -321,6 +321,16 @@
> svn_fs_mergeinfo_filter_func_t filter_func,
> void *filter_func_baton,
> apr_pool_t *pool);
> + svn_error_t *(*get_commit_revs_for_merge_ranges)(
> + apr_array_header_t **commit_rev_range_list,
> + svn_fs_root_t *root,
> + const char* merge_target,
> + const char* merge_source,
> + svn_revnum_t max_commit_rev,
> + svn_revnum_t min_commit_rev,
> + const apr_array_header_t *merge_rangelist,
> + svn_mergeinfo_inheritance_t inherit,
> + apr_pool_t *pool);
> } root_vtable_t;
>
>
>
> Modified: branches/issue-2897/subversion/libsvn_fs_base/tree.c
> URL: http://svn.collab.net/viewvc/svn/branches/issue-2897/subversion/libsvn_fs_base/tree.c?pathrev=27982&r1=27981&r2=27982
> ==============================================================================
> --- branches/issue-2897/subversion/libsvn_fs_base/tree.c (original)
> +++ branches/issue-2897/subversion/libsvn_fs_base/tree.c Thu Nov 22 11:35:07 2007
> @@ -4634,7 +4634,8 @@
> base_merge,
> base_change_mergeinfo,
> svn_fs_mergeinfo__get_mergeinfo,
> - svn_fs_mergeinfo__get_mergeinfo_for_tree
> + svn_fs_mergeinfo__get_mergeinfo_for_tree,
> + svn_fs_mergeinfo__get_commit_revs_for_merge_ranges
> };
>
>
>
> Modified: branches/issue-2897/subversion/libsvn_fs_fs/tree.c
> URL: http://svn.collab.net/viewvc/svn/branches/issue-2897/subversion/libsvn_fs_fs/tree.c?pathrev=27982&r1=27981&r2=27982
> ==============================================================================
> --- branches/issue-2897/subversion/libsvn_fs_fs/tree.c (original)
> +++ branches/issue-2897/subversion/libsvn_fs_fs/tree.c Thu Nov 22 11:35:07 2007
> @@ -3325,7 +3325,8 @@
> fs_merge,
> fs_change_mergeinfo,
> svn_fs_mergeinfo__get_mergeinfo,
> - svn_fs_mergeinfo__get_mergeinfo_for_tree
> + svn_fs_mergeinfo__get_mergeinfo_for_tree,
> + svn_fs_mergeinfo__get_commit_revs_for_merge_ranges
> };
>
> /* Construct a new root object in FS, allocated from POOL. */
>
> Modified: branches/issue-2897/subversion/libsvn_fs_util/mergeinfo-sqlite-index.c
> URL: http://svn.collab.net/viewvc/svn/branches/issue-2897/subversion/libsvn_fs_util/mergeinfo-sqlite-index.c?pathrev=27982&r1=27981&r2=27982
> ==============================================================================
> --- branches/issue-2897/subversion/libsvn_fs_util/mergeinfo-sqlite-index.c (original)
> +++ branches/issue-2897/subversion/libsvn_fs_util/mergeinfo-sqlite-index.c Thu Nov 22 11:35:07 2007
> @@ -31,6 +31,7 @@
> #include "svn_path.h"
> #include "svn_mergeinfo.h"
> #include "svn_pools.h"
> +#include "svn_sorts.h"
>
> #include "private/svn_dep_compat.h"
> #include "private/svn_fs_sqlite.h"
> @@ -63,55 +64,56 @@
> svn_mergeinfo_inheritance_t inherit,
> apr_pool_t *pool);
>
> +static svn_error_t *
> +get_mergeinfo(sqlite3 *db,
> + apr_hash_t **mergeinfo,
> + svn_revnum_t rev,
> + const apr_array_header_t *paths,
> + svn_mergeinfo_inheritance_t inherit,
> + apr_pool_t *pool);
> +
> /* Represents "no mergeinfo". */
> static svn_merge_range_t no_mergeinfo = { SVN_INVALID_REVNUM,
> SVN_INVALID_REVNUM };
>
> /* Insert the necessary indexing data into the DB for all the merges
> - on PATH as of NEW_REV, which is provided (unparsed) in
> - MERGEINFO_STR. Use POOL for temporary allocations.*/
> + on PATH as of NEW_REV, which is provided in CURR_MERGEINFO.
> + ORIG_MERGEINFO corresponds to pre-commit mergeinfo.
> + ADDED_MERGEINFO corresponds to fresh merges in this commit.
> + 'mergeinfo' table is populated with CURR_MERGEINFO.
> + 'mergeinfo_table' table is populated with ADDED_MERGEINFO.
> + Use POOL for temporary allocations.*/
> +
> static svn_error_t *
> index_path_mergeinfo(svn_revnum_t new_rev,
> sqlite3 *db,
> const char *path,
> - svn_string_t *mergeinfo_str,
> + apr_hash_t *curr_mergeinfo,
> + apr_hash_t *orig_mergeinfo,
> + apr_hash_t *added_mergeinfo,
> apr_pool_t *pool)
> {
> - apr_hash_t *mergeinfo;
> apr_hash_index_t *hi;
> sqlite3_stmt *stmt;
> svn_boolean_t remove_mergeinfo = FALSE;
>
> - SVN_ERR(svn_mergeinfo_parse(&mergeinfo, mergeinfo_str->data, pool));
> -
> - if (apr_hash_count(mergeinfo) == 0)
> + if (apr_hash_count(curr_mergeinfo) == 0)
> {
> + if (orig_mergeinfo == NULL)
> + /* There was previously no mergeinfo, inherited or explicit,
> + for PATH. */
> + return SVN_NO_ERROR;
> +
> /* All mergeinfo has been removed from PATH (or explicitly set
> to "none", if there previously was no mergeinfo). Find all
> previous mergeinfo, and (further below) insert dummy records
> representing "no mergeinfo" for all its previous merge
> - sources of PATH.
> -
> - Even though POOL is for temporary allocations, invocation of
> - get_mergeinfo_for_path() necessitates its own sub-pool. */
> - apr_pool_t *subpool = svn_pool_create(pool);
> - apr_hash_t *cache = apr_hash_make(subpool);
> + sources of PATH. */
> remove_mergeinfo = TRUE;
> - SVN_ERR(get_mergeinfo_for_path(db, path, new_rev, mergeinfo, cache,
> - svn_mergeinfo_inherited, subpool));
> - mergeinfo = apr_hash_get(mergeinfo, path, APR_HASH_KEY_STRING);
> - if (mergeinfo)
> - mergeinfo = svn_mergeinfo_dup(mergeinfo, pool);
> -
> - svn_pool_destroy(subpool);
> -
> - if (mergeinfo == NULL)
> - /* There was previously no mergeinfo, inherited or explicit,
> - for PATH. */
> - return SVN_NO_ERROR;
> + curr_mergeinfo = orig_mergeinfo;
> }
>
> - for (hi = apr_hash_first(NULL, mergeinfo);
> + for (hi = apr_hash_first(NULL, curr_mergeinfo);
> hi != NULL;
> hi = apr_hash_next(hi))
> {
> @@ -171,19 +173,51 @@
> SVN_FS__SQLITE_ERR(sqlite3_finalize(stmt), db);
> }
> }
> - SVN_FS__SQLITE_ERR(sqlite3_prepare(db,
> - "INSERT INTO mergeinfo_changed (revision, path) "
> - "VALUES (?, ?);", -1, &stmt, NULL),
> - db);
> - SVN_FS__SQLITE_ERR(sqlite3_bind_int64(stmt, 1, new_rev), db);
> -
> - SVN_FS__SQLITE_ERR(sqlite3_bind_text(stmt, 2, path, -1, SQLITE_TRANSIENT),
> - db);
> -
> - SVN_ERR(svn_fs__sqlite_step_done(stmt));
>
> - SVN_FS__SQLITE_ERR(sqlite3_finalize(stmt), db);
> + for (hi = apr_hash_first(NULL, added_mergeinfo);
> + hi != NULL;
> + hi = apr_hash_next(hi))
> + {
> + const char *mergedfrom;
> + apr_array_header_t *rangelist;
> + const void *key;
> + void *val;
> + apr_hash_this(hi, &key, NULL, &val);
> + mergedfrom = key;
> + rangelist = val;
> + if (mergedfrom && rangelist)
> + {
> + int i;
> + SVN_FS__SQLITE_ERR(sqlite3_prepare(db,
> + "INSERT INTO mergeinfo_changed (revision, "
> + "mergedfrom, mergedto, mergedrevstart, "
> + "mergedrevend, inheritable) "
> + "VALUES (?, ?, ?, ?, ?, ?);", -1, &stmt,
> + NULL), db);
>
> + SVN_FS__SQLITE_ERR(sqlite3_bind_int64(stmt, 1, new_rev), db);
> + SVN_FS__SQLITE_ERR(sqlite3_bind_text(stmt, 2, mergedfrom, -1,
> + SQLITE_TRANSIENT),
> + db);
> + SVN_FS__SQLITE_ERR(sqlite3_bind_text(stmt, 3, path, -1,
> + SQLITE_TRANSIENT),
> + db);
> + for (i = 0; i < rangelist->nelts; i++)
> + {
> + const svn_merge_range_t *range =
> + APR_ARRAY_IDX(rangelist, i, svn_merge_range_t *);
> + SVN_FS__SQLITE_ERR(sqlite3_bind_int64(stmt, 4, range->start),
> + db);
> + SVN_FS__SQLITE_ERR(sqlite3_bind_int64(stmt, 5, range->end), db);
> + SVN_FS__SQLITE_ERR(sqlite3_bind_int64(stmt, 6,
> + range->inheritable),
> + db);
> + SVN_ERR(svn_fs__sqlite_step_done(stmt));
> + SVN_FS__SQLITE_ERR(sqlite3_reset(stmt), db);
> + }
> + SVN_FS__SQLITE_ERR(sqlite3_finalize(stmt), db);
> + }
> + }
> return SVN_NO_ERROR;
> }
>
> @@ -197,6 +231,19 @@
> apr_pool_t *pool)
> {
> apr_hash_index_t *hi;
> + apr_array_header_t *paths = apr_array_make(pool, 1, sizeof(const char *));
> + apr_hash_t *orig_mergeinfo_for_paths;
> + for (hi = apr_hash_first(pool, mergeinfo_for_paths);
> + hi != NULL;
> + hi = apr_hash_next(hi))
> + {
> + const void *path;
> + apr_hash_this(hi, &path, NULL, NULL);
> + APR_ARRAY_PUSH(paths, const char *) = path;
> + }
> +
> + SVN_ERR(get_mergeinfo(db, &orig_mergeinfo_for_paths, new_rev-1, paths,
> + svn_mergeinfo_inherited, pool));
>
> for (hi = apr_hash_first(pool, mergeinfo_for_paths);
> hi != NULL;
> @@ -204,10 +251,24 @@
> {
> const void *path;
> void *mergeinfo;
> + apr_hash_t *curr_mergeinfo;
> + apr_hash_t *orig_mergeinfo_for_path;
> + apr_hash_t *added_mergeinfo_for_path;
> + apr_hash_t *deleted_mergeinfo_for_path;
>
> apr_hash_this(hi, &path, NULL, &mergeinfo);
> + orig_mergeinfo_for_path = apr_hash_get(orig_mergeinfo_for_paths, path,
> + APR_HASH_KEY_STRING);
> + SVN_ERR(svn_mergeinfo_parse(&curr_mergeinfo,
> + ((svn_string_t *)mergeinfo)->data,pool));
> + SVN_ERR(svn_mergeinfo_diff(&deleted_mergeinfo_for_path,
> + &added_mergeinfo_for_path,
> + orig_mergeinfo_for_path, curr_mergeinfo, TRUE,
> + pool));
> SVN_ERR(index_path_mergeinfo(new_rev, db, (const char *) path,
> - (svn_string_t *) mergeinfo, pool));
> + curr_mergeinfo, orig_mergeinfo_for_path,
> + added_mergeinfo_for_path, pool));
> +
This loop now wants an iterpool for the parse/diff work.
> }
> return SVN_NO_ERROR;
> }
> @@ -432,8 +493,8 @@
> then it can't have mergeinfo. */
> SVN_FS__SQLITE_ERR(sqlite3_prepare(db,
> "SELECT MAX(revision) FROM "
> - "mergeinfo_changed WHERE path = ? AND "
> - "revision <= ?;",
> + "mergeinfo_changed WHERE "
> + "mergedto = ? AND revision <= ?;",
> -1, &stmt, NULL), db);
>
> SVN_FS__SQLITE_ERR(sqlite3_bind_text(stmt, 1, path, -1, SQLITE_TRANSIENT),
> @@ -536,10 +597,11 @@
>
> /* Get all paths under us. */
> SVN_FS__SQLITE_ERR(sqlite3_prepare(db,
> - "SELECT MAX(revision), path "
> + "SELECT MAX(revision), mergedto "
> "FROM mergeinfo_changed "
> - "WHERE path LIKE ? AND revision <= ? "
> - "GROUP BY path;",
> + "WHERE mergedto LIKE ? "
> + "AND revision <= ? "
> + "GROUP BY mergedto;",
> -1, &stmt, NULL), db);
>
> like_path = apr_psprintf(subpool, "%s/%%", path);
> @@ -747,3 +809,187 @@
> cleanup:
> return svn_fs__sqlite_close(db, err);
> }
> +
> +/* Helper function for 'get_commit_revs_for_merge_ranges', to identify the
> + correct PARENT_WITH_MERGEINFO where the mergeinfo of 'MERGE_TARGET'
> + has been elided to. DB is used to retrieve this data within the
> + commits 'min_commit_rev(exclusive):max_commit_rev(inclusive)'.
> +*/
> +static svn_error_t *
> +get_parent_target_path_having_mergeinfo(const char** parent_with_mergeinfo,
> + sqlite3 *db,
> + const char* merge_target,
> + svn_revnum_t min_commit_rev,
> + svn_revnum_t max_commit_rev,
> + apr_pool_t *pool)
> +{
> + sqlite3_stmt *stmt;
> + int sqlite_result;
> + svn_boolean_t has_mergeinfo = FALSE;
> + SVN_FS__SQLITE_ERR(sqlite3_prepare(db,
> + "SELECT revision FROM mergeinfo_changed WHERE"
> + " mergedto = ? AND revision between ? AND ?;",
> + -1, &stmt, NULL), db);
> + SVN_FS__SQLITE_ERR(sqlite3_bind_text(stmt, 1, merge_target,
> + -1, SQLITE_TRANSIENT),
> + db);
> + SVN_FS__SQLITE_ERR(sqlite3_bind_int64(stmt, 2, min_commit_rev+1), db);
> + SVN_FS__SQLITE_ERR(sqlite3_bind_int64(stmt, 3, max_commit_rev), db);
> + sqlite_result = sqlite3_step(stmt);
> + SVN_FS__SQLITE_ERR(sqlite3_reset(stmt), db);
> + if (sqlite_result == SQLITE_ROW)
> + {
> + *parent_with_mergeinfo = apr_pstrdup(pool, merge_target);
> + has_mergeinfo = TRUE;
> + }
> + else
> + {
> + const char *parent_path = svn_path_dirname(merge_target, pool);
> + while (strcmp(parent_path, "/"))
> + {
> + SVN_FS__SQLITE_ERR(sqlite3_bind_text(stmt, 1, parent_path, -1,
> + SQLITE_TRANSIENT), db);
> + sqlite_result = sqlite3_step(stmt);
> + SVN_FS__SQLITE_ERR(sqlite3_reset(stmt), db);
> + if (sqlite_result == SQLITE_ROW)
> + {
> + *parent_with_mergeinfo = parent_path;
> + has_mergeinfo = TRUE;
> + break;
> + }
> + else
> + parent_path = svn_path_dirname(parent_path, pool);
> + }
> + }
> +
> + SVN_FS__SQLITE_ERR(sqlite3_finalize(stmt), db);
> +
> + if (has_mergeinfo)
> + return SVN_NO_ERROR;
> + else
> + return svn_error_createf(SVN_ERR_FS_SQLITE_ERROR, NULL,
> + _("No mergeinfo for %s between revisions %ld:%ld"),
> + merge_target, min_commit_rev, max_commit_rev);
> +}
> +
> +/* Helper function for 'svn_fs_mergeinfo__get_commit_revs_for_merge_ranges'.
> + Retrieves the commit revisions for each merge range from MERGE_RANGELIST,
> + for the merge from MERGE_SOURCE to MERGE_TARGET within the time
> + > MIN_COMMIT_REV and <=MAX_COMMIT_REV.
> + INHERIT decides whether to get the commit rev from parent paths or not.
> + It uses DB for retrieving this data. Commit revisions identified are
> + populated in *COMMIT_REV_RANGELIST as each in its own
> + single rev *svn_merge_range_t.
> +*/
> +static svn_error_t *
> +get_commit_revs_for_merge_ranges(apr_array_header_t **commit_rev_rangelist,
> + sqlite3 *db,
> + const char* merge_target,
> + const char* merge_source,
> + svn_revnum_t min_commit_rev,
> + svn_revnum_t max_commit_rev,
> + const apr_array_header_t *merge_rangelist,
> + svn_mergeinfo_inheritance_t inherit,
> + apr_pool_t *pool)
> +{
> + sqlite3_stmt *stmt;
> + int sqlite_result;
> + int i;
> + const char *parent_with_mergeinfo = merge_target;
> + const char *parent_merge_source = merge_source;
> +
> + /* early return */
> + if (!merge_rangelist || !merge_rangelist->nelts)
> + return SVN_NO_ERROR;
> + if (inherit == svn_mergeinfo_inherited
> + || inherit == svn_mergeinfo_nearest_ancestor)
> + SVN_ERR(get_parent_target_path_having_mergeinfo(&parent_with_mergeinfo,
> + db, merge_target,
> + min_commit_rev,
> + max_commit_rev, pool));
> + if (strcmp(parent_with_mergeinfo, merge_target))
> + {
> + int parent_merge_src_end;
> + const char *target_base_name = merge_target
> + + strlen(parent_with_mergeinfo);
> + parent_merge_src_end = strlen(merge_source) - strlen(target_base_name);
> + parent_merge_source = apr_pstrndup(pool, merge_source,
> + parent_merge_src_end);
> + }
> + *commit_rev_rangelist = apr_array_make(pool, 0, sizeof(svn_merge_range_t *));
> + SVN_FS__SQLITE_ERR(sqlite3_prepare(db,
> + "SELECT MAX(revision) FROM mergeinfo_changed "
> + "WHERE mergedfrom = ? AND mergedto = ? "
> + "AND mergedrevstart = ? AND mergedrevend = ? "
> + "AND inheritable = ? AND revision <= ?;",
> + -1, &stmt, NULL), db);
> + SVN_FS__SQLITE_ERR(sqlite3_bind_text(stmt, 1, parent_merge_source, -1,
> + SQLITE_TRANSIENT), db);
> + SVN_FS__SQLITE_ERR(sqlite3_bind_text(stmt, 2, parent_with_mergeinfo, -1,
> + SQLITE_TRANSIENT), db);
> + SVN_FS__SQLITE_ERR(sqlite3_bind_int64(stmt, 6, max_commit_rev), db);
> + for (i = 0; i < merge_rangelist->nelts; i++)
> + {
> + const svn_merge_range_t *range = APR_ARRAY_IDX(merge_rangelist, i,
> + svn_merge_range_t *);
> + svn_merge_range_t *commit_rev_range;
> + svn_revnum_t commit_rev;
> + SVN_FS__SQLITE_ERR(sqlite3_bind_int64(stmt, 3, range->start), db);
> + SVN_FS__SQLITE_ERR(sqlite3_bind_int64(stmt, 4, range->end), db);
> + SVN_FS__SQLITE_ERR(sqlite3_bind_int64(stmt, 5, range->inheritable), db);
> + sqlite_result = sqlite3_step(stmt);
> + if (sqlite_result != SQLITE_ROW)
> + return svn_error_createf(SVN_ERR_FS_SQLITE_ERROR, NULL,
> + _("No commit rev for merge %ld:%ld from %s"
> + " on %s within %ld"), range->start,
> + range->end,
> + merge_source, merge_target, max_commit_rev);
> + commit_rev_range = apr_pcalloc(pool, sizeof(*commit_rev_range));
> + commit_rev = (svn_revnum_t) sqlite3_column_int64(stmt, 0);
> + commit_rev_range->start = commit_rev - 1;
> + commit_rev_range->end = commit_rev;
> + commit_rev_range->inheritable = TRUE;
> + APR_ARRAY_PUSH(*commit_rev_rangelist,
> + svn_merge_range_t *) = commit_rev_range;
> + SVN_FS__SQLITE_ERR(sqlite3_reset(stmt), db);
> + }
> + SVN_FS__SQLITE_ERR(sqlite3_finalize(stmt), db);
> + qsort((*commit_rev_rangelist)->elts, (*commit_rev_rangelist)->nelts,
> + (*commit_rev_rangelist)->elt_size, svn_sort_compare_ranges);
> + return SVN_NO_ERROR;
> +}
> +
> +/* Retrieves the commit revisions for each merge range from MERGE_RANGELIST,
> + for the merge from MERGE_SOURCE to MERGE_TARGET within the time
> + > MIN_COMMIT_REV and <=MAX_COMMIT_REV.
> + INHERIT decides whether to get the commit rev from parent paths or not.
> + Commit revisions identified are populated in *COMMIT_REV_RANGELIST as each
> + in its own single rev *svn_merge_range_t.
> +*/
> +svn_error_t *
> +svn_fs_mergeinfo__get_commit_revs_for_merge_ranges(
> + apr_array_header_t **commit_rev_rangelist,
> + svn_fs_root_t *root,
> + const char* merge_target,
> + const char* merge_source,
> + svn_revnum_t min_commit_rev,
> + svn_revnum_t max_commit_rev,
> + const apr_array_header_t *merge_rangelist,
> + svn_mergeinfo_inheritance_t inherit,
> + apr_pool_t *pool)
> +{
> + sqlite3 *db;
> + svn_error_t *err;
> +
> + /* We require a revision root. */
> + if (root->is_txn_root)
> + return svn_error_create(SVN_ERR_FS_NOT_REVISION_ROOT, NULL, NULL);
> +
> + SVN_ERR(svn_fs__sqlite_open(&db, root->fs->path, pool));
> + err = get_commit_revs_for_merge_ranges(commit_rev_rangelist, db,
> + merge_target, merge_source,
> + min_commit_rev, max_commit_rev,
> + merge_rangelist, inherit, pool);
> + SVN_ERR(svn_fs__sqlite_close(db, err));
> + return SVN_NO_ERROR;
> +}
>
> Modified: branches/issue-2897/subversion/libsvn_fs_util/sqlite-util.c
> URL: http://svn.collab.net/viewvc/svn/branches/issue-2897/subversion/libsvn_fs_util/sqlite-util.c?pathrev=27982&r1=27981&r2=27982
> ==============================================================================
> --- branches/issue-2897/subversion/libsvn_fs_util/sqlite-util.c (original)
> +++ branches/issue-2897/subversion/libsvn_fs_util/sqlite-util.c Thu Nov 22 11:35:07 2007
> @@ -103,15 +103,15 @@
> APR_EOL_STR
> "CREATE INDEX mi_revision_idx ON mergeinfo (revision);"
> APR_EOL_STR
> - "CREATE TABLE mergeinfo_changed (revision INTEGER NOT NULL, path TEXT "
> - "NOT NULL);"
> + "CREATE TABLE mergeinfo_changed (revision INTEGER NOT NULL, mergedfrom TEXT "
> + "NOT NULL, mergedto TEXT NOT NULL, mergedrevstart INTEGER NOT NULL, "
> + "mergedrevend INTEGER NOT NULL, inheritable INTEGER NOT NULL);"
> + APR_EOL_STR
> + "CREATE UNIQUE INDEX "
> + "mi_c_merge_source_target_revstart_end_commit_rev_idx "
> + "ON mergeinfo_changed (mergedfrom, mergedto, mergedrevstart, "
> + "mergedrevend, inheritable, revision);"
> APR_EOL_STR
> - "CREATE UNIQUE INDEX mi_c_revpath_idx ON mergeinfo_changed (revision, path);"
> - APR_EOL_STR
> - "CREATE INDEX mi_c_path_idx ON mergeinfo_changed (path);"
> - APR_EOL_STR
> - "CREATE INDEX mi_c_revision_idx ON mergeinfo_changed (revision);"
> - APR_EOL_STR,
>
> /* USER_VERSION 2 */
> "CREATE TABLE node_origins (node_id TEXT NOT NULL, node_rev_id TEXT NOT "
>
> Modified: branches/issue-2897/subversion/libsvn_ra/ra_loader.c
> URL: http://svn.collab.net/viewvc/svn/branches/issue-2897/subversion/libsvn_ra/ra_loader.c?pathrev=27982&r1=27981&r2=27982
> ==============================================================================
> --- branches/issue-2897/subversion/libsvn_ra/ra_loader.c (original)
> +++ branches/issue-2897/subversion/libsvn_ra/ra_loader.c Thu Nov 22 11:35:07 2007
> @@ -666,6 +666,24 @@
> revision, inherit, pool);
> }
>
> +svn_error_t *svn_ra_get_commit_revs_for_merge_ranges(
> + svn_ra_session_t *session,
> + apr_array_header_t **commit_rev_rangelist,
> + const char* merge_target,
> + const char* merge_source,
> + svn_revnum_t min_commit_rev,
> + svn_revnum_t max_commit_rev,
> + const apr_array_header_t *merge_rangelist,
> + svn_mergeinfo_inheritance_t inherit,
> + apr_pool_t *pool)
> +{
> + return session->vtable->get_commit_revs_for_merge_ranges(session,
> + commit_rev_rangelist, merge_target,
> + merge_source, min_commit_rev,
> + max_commit_rev, merge_rangelist,
> + inherit, pool);
> +}
> +
> svn_error_t *svn_ra_do_update2(svn_ra_session_t *session,
> const svn_ra_reporter3_t **reporter,
> void **report_baton,
>
> Modified: branches/issue-2897/subversion/libsvn_ra/ra_loader.h
> URL: http://svn.collab.net/viewvc/svn/branches/issue-2897/subversion/libsvn_ra/ra_loader.h?pathrev=27982&r1=27981&r2=27982
> ==============================================================================
> --- branches/issue-2897/subversion/libsvn_ra/ra_loader.h (original)
> +++ branches/issue-2897/subversion/libsvn_ra/ra_loader.h Thu Nov 22 11:35:07 2007
> @@ -246,6 +246,17 @@
> svn_ra_replay_revfinish_callback_t revfinish_func,
> void *replay_baton,
> apr_pool_t *pool);
> + svn_error_t *
> + (*get_commit_revs_for_merge_ranges)(
> + svn_ra_session_t *session,
> + apr_array_header_t **commit_rev_range_list,
> + const char* merge_target,
> + const char* merge_source,
> + svn_revnum_t min_commit_rev,
> + svn_revnum_t max_commit_rev,
> + const apr_array_header_t *merge_rangelist,
> + svn_mergeinfo_inheritance_t inherit,
> + apr_pool_t *pool);
> } svn_ra__vtable_t;
>
> /* The RA session object. */
>
> Modified: branches/issue-2897/subversion/libsvn_ra_local/ra_plugin.c
> URL: http://svn.collab.net/viewvc/svn/branches/issue-2897/subversion/libsvn_ra_local/ra_plugin.c?pathrev=27982&r1=27981&r2=27982
> ==============================================================================
> --- branches/issue-2897/subversion/libsvn_ra_local/ra_plugin.c (original)
> +++ branches/issue-2897/subversion/libsvn_ra_local/ra_plugin.c Thu Nov 22 11:35:07 2007
> @@ -687,6 +687,29 @@
> return SVN_NO_ERROR;
> }
>
> +static svn_error_t *
> +svn_ra_local__get_commit_revs_for_merge_ranges(
> + svn_ra_session_t *session,
> + apr_array_header_t **commit_rev_range_list,
> + const char* merge_target,
> + const char* merge_source,
> + svn_revnum_t min_commit_rev,
> + svn_revnum_t max_commit_rev,
> + const apr_array_header_t *merge_rangelist,
> + svn_mergeinfo_inheritance_t inherit,
> + apr_pool_t *pool)
> +{
> + svn_ra_local__session_baton_t *sess = session->priv;
> + SVN_ERR(svn_repos_get_commit_revs_for_merge_ranges(commit_rev_range_list,
> + sess->repos, merge_target,
> + merge_source,
> + min_commit_rev,
> + max_commit_rev,
> + merge_rangelist,
> + inherit, NULL, NULL,
> + pool));
> + return SVN_NO_ERROR;
> +}
>
> static svn_error_t *
> svn_ra_local__do_update(svn_ra_session_t *session,
> @@ -1413,7 +1436,8 @@
> svn_ra_local__get_locks,
> svn_ra_local__replay,
> svn_ra_local__has_capability,
> - svn_ra_local__replay_range
> + svn_ra_local__replay_range,
> + svn_ra_local__get_commit_revs_for_merge_ranges
> };
>
>
>
> Modified: branches/issue-2897/subversion/libsvn_ra_neon/mergeinfo.c
> URL: http://svn.collab.net/viewvc/svn/branches/issue-2897/subversion/libsvn_ra_neon/mergeinfo.c?pathrev=27982&r1=27981&r2=27982
> ==============================================================================
> --- branches/issue-2897/subversion/libsvn_ra_neon/mergeinfo.c (original)
> +++ branches/issue-2897/subversion/libsvn_ra_neon/mergeinfo.c Thu Nov 22 11:35:07 2007
> @@ -52,6 +52,8 @@
> static const svn_ra_neon__xml_elm_t mergeinfo_report_elements[] =
> {
> { SVN_XML_NAMESPACE, SVN_DAV__MERGEINFO_REPORT, ELEM_mergeinfo_report, 0 },
> + { SVN_XML_NAMESPACE, SVN_DAV__COMMIT_REVS_FOR_MERGE_RANGES_REPORT,
> + ELEM_mergeinfo_report, 0 },
> { SVN_XML_NAMESPACE, "mergeinfo-item", ELEM_mergeinfo_item, 0 },
> { SVN_XML_NAMESPACE, "mergeinfo-path", ELEM_mergeinfo_path,
> SVN_RA_NEON__XML_CDATA },
> @@ -248,3 +250,121 @@
>
> return mb.err;
> }
> +
> +/* Request a commit-revs-for-merge-ranges-report from the URL attached to
> + SESSION, and fill in the commit_rev_rangelist array with the results.*/
> +svn_error_t *
> +svn_ra_neon__get_commit_revs_for_merge_ranges(
> + svn_ra_session_t *session,
> + apr_array_header_t **commit_rev_rangelist,
> + const char* merge_target,
> + const char* merge_source,
> + svn_revnum_t min_commit_rev,
> + svn_revnum_t max_commit_rev,
> + const apr_array_header_t *merge_rangelist,
> + svn_mergeinfo_inheritance_t inherit,
> + apr_pool_t *pool)
> +{
> + svn_error_t *err;
> + int status_code;
> + svn_ra_neon__session_t *ras = session->priv;
> + svn_stringbuf_t *request_body = svn_stringbuf_create("", pool);
> + struct mergeinfo_baton mb;
> + svn_string_t bc_url, bc_relative;
> + svn_stringbuf_t *merge_rangelist_str;
> + const char *final_bc_url;
> +
> + static const char minfo_report_head[] =
> + "<S:" SVN_DAV__COMMIT_REVS_FOR_MERGE_RANGES_REPORT
> + " xmlns:S=\"" SVN_XML_NAMESPACE "\">"
> + DEBUG_CR;
> +
> + static const char minfo_report_tail[] =
> + "</S:" SVN_DAV__COMMIT_REVS_FOR_MERGE_RANGES_REPORT ">" DEBUG_CR;
> +
> + /* Construct the request body. */
> + svn_stringbuf_appendcstr(request_body, minfo_report_head);
> + svn_stringbuf_appendcstr(request_body, "<S:merge-target>");
> + svn_stringbuf_appendcstr(request_body,
> + apr_xml_quote_string(pool, merge_target, 0));
> + svn_stringbuf_appendcstr(request_body, "</S:merge-target>");
> + svn_stringbuf_appendcstr(request_body, "<S:merge-source>");
> + svn_stringbuf_appendcstr(request_body,
> + apr_xml_quote_string(pool, merge_source, 0));
> + svn_stringbuf_appendcstr(request_body, "</S:merge-source>");
> + svn_stringbuf_appendcstr(request_body,
> + apr_psprintf(pool,
> + "<S:min-commit-revision>%ld"
> + "</S:min-commit-revision>",
> + min_commit_rev));
> + svn_stringbuf_appendcstr(request_body,
> + apr_psprintf(pool,
> + "<S:max-commit-revision>%ld"
> + "</S:max-commit-revision>",
> + max_commit_rev));
> + SVN_ERR(svn_rangelist_to_stringbuf(&merge_rangelist_str, merge_rangelist,
> + pool));
> + svn_stringbuf_appendcstr(request_body, "<S:merge-ranges>");
> + svn_stringbuf_appendcstr(request_body, merge_rangelist_str->data);
> + svn_stringbuf_appendcstr(request_body, "</S:merge-ranges>");
> + svn_stringbuf_appendcstr(request_body,
> + apr_psprintf(pool,
> + "<S:inherit>%s"
> + "</S:inherit>",
> + svn_inheritance_to_word(inherit)));
> +
> + svn_stringbuf_appendcstr(request_body, minfo_report_tail);
> +
> + mb.pool = pool;
> + mb.curr_path = NULL;
> + mb.curr_info = svn_stringbuf_create("", pool);
> + mb.result = apr_hash_make(pool);
> + mb.err = SVN_NO_ERROR;
> +
> + /* ras's URL may not exist in HEAD, and thus it's not safe to send
> + it as the main argument to the REPORT request; it might cause
> + dav_get_resource() to choke on the server. So instead, we pass a
> + baseline-collection URL, which we get from END. */
> + SVN_ERR(svn_ra_neon__get_baseline_info(NULL, &bc_url, &bc_relative, NULL,
> + ras, ras->url->data, max_commit_rev,
> + pool));
> + final_bc_url = svn_path_url_add_component(bc_url.data, bc_relative.data,
> + pool);
> +
> + err = svn_ra_neon__parsed_request(ras,
> + "REPORT",
> + final_bc_url,
> + request_body->data,
> + NULL, NULL,
> + start_element,
> + cdata_handler,
> + end_element,
> + &mb,
> + NULL,
> + &status_code,
> + FALSE,
> + pool);
> + /* If the server responds with HTTP_NOT_IMPLEMENTED, assume its
> + mod_dav_svn is too old to understand the "mergeinfo-report" REPORT.
> +
> + ### It would be less expensive if we knew the server's
> + ### capabilities *before* sending our REPORT. */
> + if (status_code == 501)
> + {
> + *commit_rev_rangelist = apr_array_make(pool, 0,
> + sizeof(svn_merge_range_t *));
> + svn_error_clear(err);
> + }
> + else if (err)
> + return err;
> + else if (mb.err == SVN_NO_ERROR)
> + {
> + apr_hash_t *target_mergeinfo = apr_hash_get(mb.result, merge_target,
> + APR_HASH_KEY_STRING);
> + if (target_mergeinfo)
> + *commit_rev_rangelist = apr_hash_get(target_mergeinfo, merge_source,
> + APR_HASH_KEY_STRING);
> + }
> +
> + return mb.err;
> +}
>
> Modified: branches/issue-2897/subversion/libsvn_ra_neon/ra_neon.h
> URL: http://svn.collab.net/viewvc/svn/branches/issue-2897/subversion/libsvn_ra_neon/ra_neon.h?pathrev=27982&r1=27981&r2=27982
> ==============================================================================
> --- branches/issue-2897/subversion/libsvn_ra_neon/ra_neon.h (original)
> +++ branches/issue-2897/subversion/libsvn_ra_neon/ra_neon.h Thu Nov 22 11:35:07 2007
> @@ -262,6 +262,17 @@
> svn_mergeinfo_inheritance_t inherit,
> apr_pool_t *pool);
>
> +svn_error_t * svn_ra_neon__get_commit_revs_for_merge_ranges(
> + svn_ra_session_t *session,
> + apr_array_header_t **commit_rev_rangelist,
> + const char* merge_target,
> + const char* merge_source,
> + svn_revnum_t min_commit_rev,
> + svn_revnum_t max_commit_rev,
> + const apr_array_header_t *merge_rangelist,
> + svn_mergeinfo_inheritance_t inherit,
> + apr_pool_t *pool);
> +
> svn_error_t * svn_ra_neon__do_update(svn_ra_session_t *session,
> const svn_ra_reporter3_t **reporter,
> void **report_baton,
>
> Modified: branches/issue-2897/subversion/libsvn_ra_neon/session.c
> URL: http://svn.collab.net/viewvc/svn/branches/issue-2897/subversion/libsvn_ra_neon/session.c?pathrev=27982&r1=27981&r2=27982
> ==============================================================================
> --- branches/issue-2897/subversion/libsvn_ra_neon/session.c (original)
> +++ branches/issue-2897/subversion/libsvn_ra_neon/session.c Thu Nov 22 11:35:07 2007
> @@ -1168,7 +1168,8 @@
> svn_ra_neon__get_locks,
> svn_ra_neon__replay,
> svn_ra_neon__has_capability,
> - svn_ra_neon__replay_range
> + svn_ra_neon__replay_range,
> + svn_ra_neon__get_commit_revs_for_merge_ranges
> };
>
> svn_error_t *
>
> Modified: branches/issue-2897/subversion/libsvn_ra_serf/mergeinfo.c
> URL: http://svn.collab.net/viewvc/svn/branches/issue-2897/subversion/libsvn_ra_serf/mergeinfo.c?pathrev=27982&r1=27981&r2=27982
> ==============================================================================
> --- branches/issue-2897/subversion/libsvn_ra_serf/mergeinfo.c (original)
> +++ branches/issue-2897/subversion/libsvn_ra_serf/mergeinfo.c Thu Nov 22 11:35:07 2007
> @@ -49,14 +49,24 @@
> CDATA from the mergeinfo items as we get them from the server. */
>
> typedef struct {
> +/* Needed by both mergeinfo reports. */
> apr_pool_t *pool;
> svn_stringbuf_t *curr_path;
> svn_stringbuf_t *curr_info;
> apr_hash_t *result;
> svn_boolean_t done;
> + svn_mergeinfo_inheritance_t inherit;
> +
> +/* Needed by only mergeinfo-report. */
> const apr_array_header_t *paths;
> svn_revnum_t revision;
> - svn_mergeinfo_inheritance_t inherit;
> +
> +/* Needed by only commit-revs-for-merge-ranges-report. */
> + const char *merge_target;
> + const char *merge_source;
> + svn_revnum_t min_commit_rev;
> + svn_revnum_t max_commit_rev;
> + svn_stringbuf_t *merge_rangelist_str;
> } mergeinfo_context_t;
>
> static svn_error_t *
> @@ -69,7 +79,10 @@
> mergeinfo_state_e state;
>
> state = parser->state->current_state;
> - if (state == NONE && strcmp(name.name, SVN_DAV__MERGEINFO_REPORT) == 0)
> + if (state == NONE &&
> + (strcmp(name.name, SVN_DAV__MERGEINFO_REPORT) == 0
> + || strcmp(name.name, SVN_DAV__COMMIT_REVS_FOR_MERGE_RANGES_REPORT) == 0)
> + )
> {
> svn_ra_serf__xml_push_state(parser, MERGE_INFO_REPORT);
> }
> @@ -103,7 +116,9 @@
> state = parser->state->current_state;
>
> if (state == MERGE_INFO_REPORT &&
> - strcmp(name.name, SVN_DAV__MERGEINFO_REPORT) == 0)
> + (strcmp(name.name, SVN_DAV__MERGEINFO_REPORT) == 0
> + || strcmp(name.name, SVN_DAV__COMMIT_REVS_FOR_MERGE_RANGES_REPORT) == 0)
> + )
> {
> svn_ra_serf__xml_pop_state(parser);
> }
> @@ -169,8 +184,59 @@
> #define MINFO_REQ_TAIL "</S:" SVN_DAV__MERGEINFO_REPORT ">"
>
> static serf_bucket_t *
> -create_mergeinfo_body(void *baton,
> - serf_bucket_alloc_t *alloc,
> +create_commit_revs_for_merge_ranges_body(void *baton,
> + serf_bucket_alloc_t *alloc,
> + apr_pool_t *pool)
> +{
> + mergeinfo_context_t *mergeinfo_ctx = baton;
> + serf_bucket_t *body_bkt, *tmp_bkt;
> + static const char minfo_report_head[] =
> + "<S:" SVN_DAV__COMMIT_REVS_FOR_MERGE_RANGES_REPORT
> + " xmlns:S=\"" SVN_XML_NAMESPACE "\">";
> +
> + static const char minfo_report_tail[] =
> + "</S:" SVN_DAV__COMMIT_REVS_FOR_MERGE_RANGES_REPORT ">";
> +
> + body_bkt = serf_bucket_aggregate_create(alloc);
> +
> + tmp_bkt = SERF_BUCKET_SIMPLE_STRING_LEN(minfo_report_head,
> + strlen(minfo_report_head), alloc);
> + serf_bucket_aggregate_append(body_bkt, tmp_bkt);
> + svn_ra_serf__add_tag_buckets(body_bkt, "S:" SVN_DAV__MERGE_TARGET,
> + apr_xml_quote_string(pool,
> + mergeinfo_ctx->merge_target,
> + 0),
> + alloc);
> +
> + svn_ra_serf__add_tag_buckets(body_bkt, "S:" SVN_DAV__MERGE_SOURCE,
> + apr_xml_quote_string(pool,
> + mergeinfo_ctx->merge_source,
> + 0),
> + alloc);
> +
> + svn_ra_serf__add_tag_buckets(body_bkt,
> + "S:" SVN_DAV__MIN_COMMIT_REVISION,
> + apr_ltoa(pool, mergeinfo_ctx->min_commit_rev),
> + alloc);
> + svn_ra_serf__add_tag_buckets(body_bkt,
> + "S:" SVN_DAV__MAX_COMMIT_REVISION,
> + apr_ltoa(pool, mergeinfo_ctx->max_commit_rev),
> + alloc);
> + svn_ra_serf__add_tag_buckets(body_bkt, "S:" SVN_DAV__MERGE_RANGES,
> + mergeinfo_ctx->merge_rangelist_str->data,
> + alloc);
> + svn_ra_serf__add_tag_buckets(body_bkt, "S:" SVN_DAV__INHERIT,
> + svn_inheritance_to_word(mergeinfo_ctx->inherit),
> + alloc);
> + tmp_bkt = SERF_BUCKET_SIMPLE_STRING_LEN(minfo_report_tail,
> + strlen(minfo_report_tail), alloc);
> + serf_bucket_aggregate_append(body_bkt, tmp_bkt);
> +
> + return body_bkt;
> +}
> +
> +static serf_bucket_t *
> +create_mergeinfo_body(void *baton, serf_bucket_alloc_t *alloc,
> apr_pool_t *pool)
> {
> mergeinfo_context_t *mergeinfo_ctx = baton;
> @@ -305,3 +371,112 @@
>
> return SVN_NO_ERROR;
> }
> +
> +/* Request a commit-revs-for-merge-ranges-report from the URL attached to
> + SESSION, and fill in the commit_rev_rangelist array with the results.*/
> +svn_error_t *
> +svn_ra_serf__get_commit_revs_for_merge_ranges(
> + svn_ra_session_t *ra_session,
> + apr_array_header_t **commit_rev_rangelist,
> + const char* merge_target,
> + const char* merge_source,
> + svn_revnum_t min_commit_rev,
> + svn_revnum_t max_commit_rev,
> + const apr_array_header_t *merge_rangelist,
> + svn_mergeinfo_inheritance_t inherit,
> + apr_pool_t *pool)
> +{
> + svn_error_t *err;
> + int status_code;
> +
> + mergeinfo_context_t *mergeinfo_ctx;
> + svn_ra_serf__session_t *session = ra_session->priv;
> + svn_ra_serf__handler_t *handler;
> + svn_ra_serf__xml_parser_t *parser_ctx;
> + const char *relative_url, *basecoll_url;
> + const char *path;
> +
> + SVN_ERR(svn_ra_serf__get_baseline_info(&basecoll_url, &relative_url,
> + session, NULL, max_commit_rev, pool));
> +
> + path = svn_path_url_add_component(basecoll_url, relative_url, pool);
> +
> + mergeinfo_ctx = apr_pcalloc(pool, sizeof(*mergeinfo_ctx));
> + mergeinfo_ctx->pool = pool;
> + mergeinfo_ctx->curr_path = svn_stringbuf_create("", pool);
> + mergeinfo_ctx->curr_info = svn_stringbuf_create("", pool);
> + mergeinfo_ctx->done = FALSE;
> + mergeinfo_ctx->result = apr_hash_make(pool);
> + mergeinfo_ctx->merge_target = merge_target;
> + mergeinfo_ctx->merge_source = merge_source;
> + mergeinfo_ctx->min_commit_rev = min_commit_rev;
> + mergeinfo_ctx->max_commit_rev = max_commit_rev;
> + SVN_ERR(svn_rangelist_to_stringbuf(&(mergeinfo_ctx->merge_rangelist_str),
> + merge_rangelist, pool));
> + mergeinfo_ctx->inherit = inherit;
> +
> + handler = apr_pcalloc(pool, sizeof(*handler));
> +
> + handler->method = "REPORT";
> + handler->path = path;
> + handler->conn = session->conns[0];
> + handler->session = session;
> + handler->body_delegate = create_commit_revs_for_merge_ranges_body;
> + handler->body_delegate_baton = mergeinfo_ctx;
> + handler->body_type = "text/xml";
> +
> + parser_ctx = apr_pcalloc(pool, sizeof(*parser_ctx));
> +
> + parser_ctx->pool = pool;
> + parser_ctx->user_data = mergeinfo_ctx;
> + parser_ctx->start = start_element;
> + parser_ctx->end = end_element;
> + parser_ctx->cdata = cdata_handler;
> + parser_ctx->done = &mergeinfo_ctx->done;
> + parser_ctx->status_code = &status_code;
> +
> + handler->response_handler = svn_ra_serf__handle_xml_parser;
> + handler->response_baton = parser_ctx;
> +
> + svn_ra_serf__request_create(handler);
> +
> + err = svn_ra_serf__context_run_wait(&mergeinfo_ctx->done, session, pool);
> +
> + if (status_code == 404)
> + {
> + svn_error_clear(err);
> + return svn_error_createf(SVN_ERR_RA_DAV_PATH_NOT_FOUND, NULL,
> + "'%s' path not found",
> + handler->path);
> + }
> +
> + /* If the server responds with HTTP_NOT_IMPLEMENTED (which ra_serf
> + translates into a Subversion error), assume its mod_dav_svn is
> + too old to understand the mergeinfo-report REPORT.
> +
> + ### It would be less expensive if we knew the server's
> + ### capabilities *before* sending our REPORT. */
> + if (err)
> + {
> + if (err->apr_err == SVN_ERR_UNSUPPORTED_FEATURE)
> + {
> + *commit_rev_rangelist = apr_array_make(pool, 0,
> + sizeof(svn_merge_range_t *));
> +
> + svn_error_clear(err);
> + }
> + else
> + return err;
> + }
> +
> + if (mergeinfo_ctx->done)
> + {
> + apr_hash_t *target_mergeinfo = apr_hash_get(mergeinfo_ctx->result,
> + merge_target,
> + APR_HASH_KEY_STRING);
> + if (target_mergeinfo)
> + *commit_rev_rangelist = apr_hash_get(target_mergeinfo, merge_source,
> + APR_HASH_KEY_STRING);
> + }
> + return SVN_NO_ERROR;
> +}
>
> Modified: branches/issue-2897/subversion/libsvn_ra_serf/ra_serf.h
> URL: http://svn.collab.net/viewvc/svn/branches/issue-2897/subversion/libsvn_ra_serf/ra_serf.h?pathrev=27982&r1=27981&r2=27982
> ==============================================================================
> --- branches/issue-2897/subversion/libsvn_ra_serf/ra_serf.h (original)
> +++ branches/issue-2897/subversion/libsvn_ra_serf/ra_serf.h Thu Nov 22 11:35:07 2007
> @@ -1164,6 +1164,17 @@
> svn_mergeinfo_inheritance_t inherit,
> apr_pool_t *pool);
>
> +svn_error_t * svn_ra_serf__get_commit_revs_for_merge_ranges(
> + svn_ra_session_t *session,
> + apr_array_header_t **commit_rev_rangelist,
> + const char* merge_target,
> + const char* merge_source,
> + svn_revnum_t min_commit_rev,
> + svn_revnum_t max_commit_rev,
> + const apr_array_header_t *merge_rangelist,
> + svn_mergeinfo_inheritance_t inherit,
> + apr_pool_t *pool);
> +
> /* Implements the has_capability RA layer function. */
> svn_error_t *
> svn_ra_serf__has_capability(svn_ra_session_t *ra_session,
>
> Modified: branches/issue-2897/subversion/libsvn_ra_serf/serf.c
> URL: http://svn.collab.net/viewvc/svn/branches/issue-2897/subversion/libsvn_ra_serf/serf.c?pathrev=27982&r1=27981&r2=27982
> ==============================================================================
> --- branches/issue-2897/subversion/libsvn_ra_serf/serf.c (original)
> +++ branches/issue-2897/subversion/libsvn_ra_serf/serf.c Thu Nov 22 11:35:07 2007
> @@ -1015,6 +1015,7 @@
> svn_ra_serf__replay,
> svn_ra_serf__has_capability,
> svn_ra_serf__replay_range,
> + svn_ra_serf__get_commit_revs_for_merge_ranges
> };
>
> svn_error_t *
>
> Modified: branches/issue-2897/subversion/libsvn_ra_svn/client.c
> URL: http://svn.collab.net/viewvc/svn/branches/issue-2897/subversion/libsvn_ra_svn/client.c?pathrev=27982&r1=27981&r2=27982
> ==============================================================================
> --- branches/issue-2897/subversion/libsvn_ra_svn/client.c (original)
> +++ branches/issue-2897/subversion/libsvn_ra_svn/client.c Thu Nov 22 11:35:07 2007
> @@ -1098,6 +1098,47 @@
>
> return SVN_NO_ERROR;
> }
> +static svn_error_t *
> +ra_svn_get_commit_revs_for_merge_ranges(
> + svn_ra_session_t *session,
> + apr_array_header_t **commit_rev_rangelist,
> + const char* merge_target,
> + const char* merge_source,
> + svn_revnum_t min_commit_rev,
> + svn_revnum_t max_commit_rev,
> + const apr_array_header_t *merge_rangelist,
> + svn_mergeinfo_inheritance_t inherit,
> + apr_pool_t *pool)
> +{
> + svn_ra_svn__session_baton_t *sess_baton = session->priv;
> + svn_ra_svn_conn_t *conn = sess_baton->conn;
> + apr_hash_t *mergeinfo;
> + svn_stringbuf_t *merge_rangelist_str;
> + char *mergeinfo_str;
> + SVN_ERR(svn_rangelist_to_stringbuf(&merge_rangelist_str, merge_rangelist,
> + pool));
> +
> + if (!svn_ra_svn_has_capability(conn, SVN_RA_SVN_CAP_MERGEINFO))
> + {
> + *commit_rev_rangelist = apr_array_make(pool, 0,
> + sizeof(svn_merge_range_t *));
> + return SVN_NO_ERROR;
> + }
> +
> + SVN_ERR(svn_ra_svn_write_tuple(conn, pool, "w(ccrrcw)",
> + "commit-revs-for-merge-ranges",
> + merge_target, merge_source, min_commit_rev,
> + max_commit_rev, merge_rangelist_str->data,
> + svn_inheritance_to_word(inherit)));
> +
> + SVN_ERR(handle_auth_request(sess_baton, pool));
> + SVN_ERR(svn_ra_svn_read_cmd_response(conn, pool, "c", &mergeinfo_str));
> +
> + SVN_ERR(svn_mergeinfo_parse(&mergeinfo, mergeinfo_str, pool));
> + *commit_rev_rangelist = apr_hash_get(mergeinfo, merge_source,
> + APR_HASH_KEY_STRING);
> + return SVN_NO_ERROR;
> +}
>
> static svn_error_t *ra_svn_update(svn_ra_session_t *session,
> const svn_ra_reporter3_t **reporter,
> @@ -2273,6 +2314,7 @@
> ra_svn_replay,
> ra_svn_has_capability,
> ra_svn_replay_range,
> + ra_svn_get_commit_revs_for_merge_ranges
> };
>
> svn_error_t *
>
> Modified: branches/issue-2897/subversion/libsvn_repos/fs-wrap.c
> URL: http://svn.collab.net/viewvc/svn/branches/issue-2897/subversion/libsvn_repos/fs-wrap.c?pathrev=27982&r1=27981&r2=27982
> ==============================================================================
> --- branches/issue-2897/subversion/libsvn_repos/fs-wrap.c (original)
> +++ branches/issue-2897/subversion/libsvn_repos/fs-wrap.c Thu Nov 22 11:35:07 2007
> @@ -606,7 +606,41 @@
> return SVN_NO_ERROR;
> }
>
> -
> +svn_error_t *
> +svn_repos_get_commit_revs_for_merge_ranges(
> + apr_array_header_t **commit_rev_range_list,
> + svn_repos_t *repos,
> + const char* merge_target,
> + const char* merge_source,
> + svn_revnum_t min_commit_rev,
> + svn_revnum_t max_commit_rev,
> + const apr_array_header_t *merge_rangelist,
> + svn_mergeinfo_inheritance_t inherit,
> + svn_repos_authz_func_t authz_read_func,
> + void *authz_read_baton,
> + apr_pool_t *pool)
> +{
> + svn_fs_root_t *root;
> + SVN_ERR(svn_fs_revision_root(&root, repos->fs, max_commit_rev, pool));
> + if (authz_read_func)
> + {
> + svn_boolean_t readable;
> + SVN_ERR(authz_read_func(&readable, root, merge_target,
> + authz_read_baton, pool));
> + if (!readable)
> + return svn_error_createf
> + (SVN_ERR_AUTHZ_UNREADABLE, NULL,
> + _("Read denied: not authorized to read mergeinfo on %s"),
> + merge_target);
> + }
> + SVN_ERR(svn_fs_get_commit_revs_for_merge_ranges(commit_rev_range_list,
> + root, merge_target,
> + merge_source, min_commit_rev,
> + max_commit_rev,
> + merge_rangelist, inherit,
> + pool));
> + return SVN_NO_ERROR;
> +}
>
> /*
> * vim:ts=4:sw=4:expandtab:tw=80:fo=tcroq
>
> Modified: branches/issue-2897/subversion/mod_dav_svn/dav_svn.h
> URL: http://svn.collab.net/viewvc/svn/branches/issue-2897/subversion/mod_dav_svn/dav_svn.h?pathrev=27982&r1=27981&r2=27982
> ==============================================================================
> --- branches/issue-2897/subversion/mod_dav_svn/dav_svn.h (original)
> +++ branches/issue-2897/subversion/mod_dav_svn/dav_svn.h Thu Nov 22 11:35:07 2007
> @@ -553,6 +553,10 @@
> const apr_xml_doc *doc,
> ap_filter_t *output);
> dav_error *
> +dav_svn__get_commit_revs_for_merge_ranges_report(const dav_resource *resource,
> + const apr_xml_doc *doc,
> + ap_filter_t *output);
> +dav_error *
> dav_svn__get_locks_report(const dav_resource *resource,
> const apr_xml_doc *doc,
> ap_filter_t *output);
>
> Modified: branches/issue-2897/subversion/mod_dav_svn/reports/mergeinfo.c
> URL: http://svn.collab.net/viewvc/svn/branches/issue-2897/subversion/mod_dav_svn/reports/mergeinfo.c?pathrev=27982&r1=27981&r2=27982
> ==============================================================================
> --- branches/issue-2897/subversion/mod_dav_svn/reports/mergeinfo.c (original)
> +++ branches/issue-2897/subversion/mod_dav_svn/reports/mergeinfo.c Thu Nov 22 11:35:07 2007
> @@ -30,6 +30,7 @@
> #include "svn_xml.h"
> #include "svn_path.h"
> #include "svn_dav.h"
> +#include "svn_mergeinfo.h"
> #include "private/svn_dav_protocol.h"
>
> #include "../dav_svn.h"
> @@ -200,3 +201,187 @@
> resource->pool);
> return derr;
> }
> +
> +dav_error *
> +dav_svn__get_commit_revs_for_merge_ranges_report(const dav_resource *resource,
> + const apr_xml_doc *doc,
> + ap_filter_t *output)
> +{
> + apr_status_t apr_err;
> + svn_error_t *serr;
> + dav_error *derr = NULL;
> + int ns;
> + const char *action = "get-commit-revs-for-merge-ranges";
> + apr_array_header_t *commit_rev_range_list;
> + apr_xml_elem *child;
> + /* These get determined from the request document. */
> + svn_revnum_t max_commit_rev = SVN_INVALID_REVNUM;
> + svn_revnum_t min_commit_rev = SVN_INVALID_REVNUM;
> + const char* merge_target = NULL;
> + const char* merge_source = NULL;
> + const char *merge_ranges_string = NULL;
> + apr_array_header_t *merge_rangelist;
> + /* By default look for explicit mergeinfo only. */
> + svn_mergeinfo_inheritance_t inherit = svn_mergeinfo_explicit;
> + const dav_svn_repos *repos = resource->info->repos;
> + apr_hash_t *mergeinfo = apr_hash_make(resource->pool);
> + svn_stringbuf_t *commit_rev_mergeinfo;
> + apr_bucket_brigade *bb;
> + dav_svn__authz_read_baton arb;
> + const char itemformat[] = "<S:" SVN_DAV__MERGEINFO_ITEM ">" DEBUG_CR
> + "<S:" SVN_DAV__MERGEINFO_PATH ">%s</S:" SVN_DAV__MERGEINFO_PATH ">"
> + DEBUG_CR
> + "<S:" SVN_DAV__MERGEINFO_INFO ">%s</S:" SVN_DAV__MERGEINFO_INFO ">"
> + DEBUG_CR
> + "</S:" SVN_DAV__MERGEINFO_ITEM ">";
> + /* Sanity check. */
> + ns = dav_svn__find_ns(doc->namespaces, SVN_XML_NAMESPACE);
> + if (ns == -1)
> + {
> + return dav_svn__new_error_tag(resource->pool, HTTP_BAD_REQUEST, 0,
> + "The request does not contain the 'svn:' "
> + "namespace, so it is not going to have "
> + "certain required elements.",
> + SVN_DAV_ERROR_NAMESPACE,
> + SVN_DAV_ERROR_TAG);
> + }
> + for (child = doc->root->first_child; child != NULL; child = child->next)
> + {
> + /* if this element isn't one of ours, then skip it */
> + if (child->ns != ns)
> + continue;
> +
> + if (strcmp(child->name, SVN_DAV__MAX_COMMIT_REVISION) == 0)
> + max_commit_rev = SVN_STR_TO_REV(dav_xml_get_cdata(child,
> + resource->pool, 1));
> + else if (strcmp(child->name, SVN_DAV__MIN_COMMIT_REVISION) == 0)
> + min_commit_rev = SVN_STR_TO_REV(dav_xml_get_cdata(child,
> + resource->pool, 1));
> + else if (strcmp(child->name, SVN_DAV__INHERIT) == 0)
> + inherit = svn_inheritance_from_word(
> + dav_xml_get_cdata(child, resource->pool, 1));
> + else if (strcmp(child->name, SVN_DAV__MERGE_SOURCE) == 0)
> + {
> + const char *rel_path = dav_xml_get_cdata(child, resource->pool, 0);
> + if ((derr = dav_svn__test_canonical(rel_path, resource->pool)))
> + return derr;
> + merge_source = svn_path_join(resource->info->repos_path, rel_path,
> + resource->pool);
> + }
> + else if (strcmp(child->name, SVN_DAV__MERGE_TARGET) == 0)
> + {
> + const char *rel_path = dav_xml_get_cdata(child, resource->pool, 0);
> + if ((derr = dav_svn__test_canonical(rel_path, resource->pool)))
> + return derr;
> + merge_target = svn_path_join(resource->info->repos_path, rel_path,
> + resource->pool);
> + }
> + else if (strcmp(child->name, SVN_DAV__MERGE_RANGES) == 0)
> + merge_ranges_string = dav_xml_get_cdata(child, resource->pool, 0);
> +
> + /* else unknown element; skip it */
> + }
> + {
> + /* We lack svn_rangelist_parse, so creating a dummy mergeinfo
> + and parse with the help of svn_mergeinfo_parse. */
> + apr_hash_t *dummy_mergeinfo;
> + char *dummy_mergeinfo_str = apr_pstrcat(resource->pool, merge_source, ":",
> + merge_ranges_string, NULL);
> + serr = svn_mergeinfo_parse(&dummy_mergeinfo, dummy_mergeinfo_str,
> + resource->pool);
> + if (serr)
> + {
> + derr = dav_svn__convert_err(serr, HTTP_BAD_REQUEST, NULL,
> + resource->pool);
> + goto cleanup;
> + }
> + merge_rangelist = apr_hash_get(dummy_mergeinfo, merge_source,
> + APR_HASH_KEY_STRING);
> + }
> +
> +
> + /* Build authz read baton */
> + arb.r = resource->info->r;
> + arb.repos = resource->info->repos;
> +
> + /* Build mergeinfo brigade */
> + bb = apr_brigade_create(resource->pool, output->c->bucket_alloc);
> +
> + serr = svn_repos_get_commit_revs_for_merge_ranges(
> + &commit_rev_range_list,
> + repos->repos, merge_target,
> + merge_source,
> + min_commit_rev,
> + max_commit_rev,
> + merge_rangelist,
> + inherit,
> + dav_svn__authz_read_func(&arb),
> + &arb,
> + resource->pool);
> + if (serr)
> + {
> + derr = dav_svn__convert_err(serr, HTTP_BAD_REQUEST, serr->message,
> + resource->pool);
> + goto cleanup;
> + }
> +
> + serr = dav_svn__send_xml(bb, output,
> + DAV_XML_HEADER DEBUG_CR
> + "<S:" SVN_DAV__COMMIT_REVS_FOR_MERGE_RANGES_REPORT " "
> + "xmlns:S=\"" SVN_XML_NAMESPACE "\" "
> + "xmlns:D=\"DAV:\">" DEBUG_CR);
> + if (serr)
> + {
> + derr = dav_svn__convert_err(serr, HTTP_BAD_REQUEST, serr->message,
> + resource->pool);
> + goto cleanup;
> + }
> +
> + apr_hash_set(mergeinfo, merge_source, APR_HASH_KEY_STRING,
> + commit_rev_range_list);
> + serr = svn_mergeinfo_to_stringbuf(&commit_rev_mergeinfo, mergeinfo,
> + resource->pool);
> + if (serr)
> + {
> + derr = dav_svn__convert_err(serr, HTTP_BAD_REQUEST, NULL,
> + resource->pool);
> + goto cleanup;
> + }
> +
> + serr = dav_svn__send_xml(bb, output, itemformat,
> + apr_xml_quote_string(resource->pool,
> + merge_target, 0),
> + apr_xml_quote_string(resource->pool,
> + commit_rev_mergeinfo->data,
> + 0));
> + if (serr)
> + {
> + derr = dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR,
> + "Error ending REPORT response.",
> + resource->pool);
> + goto cleanup;
> + }
> +
> + if ((serr = dav_svn__send_xml(
> + bb, output,
> + "</S:" SVN_DAV__COMMIT_REVS_FOR_MERGE_RANGES_REPORT ">"
> + DEBUG_CR)))
> + {
> + derr = dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR,
> + "Error ending REPORT response.",
> + resource->pool);
> + goto cleanup;
> + }
> +
> + cleanup:
> + apr_table_set(resource->info->r->subprocess_env, "SVN-ACTION", action);
> +
> +
> + /* Flush the contents of the brigade (returning an error only if we
> + don't already have one). */
> + if ((apr_err = ap_fflush(output, bb)) && !derr)
> + derr = dav_svn__convert_err(svn_error_create(apr_err, 0, NULL),
> + HTTP_INTERNAL_SERVER_ERROR,
> + "Error flushing brigade.", resource->pool);
> + return derr;
> +}
>
> Modified: branches/issue-2897/subversion/mod_dav_svn/version.c
> URL: http://svn.collab.net/viewvc/svn/branches/issue-2897/subversion/mod_dav_svn/version.c?pathrev=27982&r1=27981&r2=27982
> ==============================================================================
> --- branches/issue-2897/subversion/mod_dav_svn/version.c (original)
> +++ branches/issue-2897/subversion/mod_dav_svn/version.c Thu Nov 22 11:35:07 2007
> @@ -968,7 +968,12 @@
> {
> return dav_svn__get_mergeinfo_report(resource, doc, output);
> }
> -
> + else if (strcmp(doc->root->name,
> + SVN_DAV__COMMIT_REVS_FOR_MERGE_RANGES_REPORT) == 0)
> + {
> + return dav_svn__get_commit_revs_for_merge_ranges_report(resource,
> + doc, output);
> + }
> /* NOTE: if you add a report, don't forget to add it to the
> * dav_svn__reports_list[] array.
> */
>
> Modified: branches/issue-2897/subversion/svnserve/serve.c
> URL: http://svn.collab.net/viewvc/svn/branches/issue-2897/subversion/svnserve/serve.c?pathrev=27982&r1=27981&r2=27982
> ==============================================================================
> --- branches/issue-2897/subversion/svnserve/serve.c (original)
> +++ branches/issue-2897/subversion/svnserve/serve.c Thu Nov 22 11:35:07 2007
> @@ -1513,6 +1513,62 @@
> return SVN_NO_ERROR;
> }
>
> +static svn_error_t *get_commit_revs_for_merge_ranges(svn_ra_svn_conn_t *conn,
> + apr_pool_t *pool,
> + apr_array_header_t *params,
> + void *baton)
> +{
> + server_baton_t *b = baton;
> + apr_array_header_t *commit_rev_range_list;
> + const char *inherit_word;
> + svn_revnum_t max_commit_rev = SVN_INVALID_REVNUM;
> + svn_revnum_t min_commit_rev = SVN_INVALID_REVNUM;
> + const char* merge_target = NULL;
> + const char* merge_source = NULL;
> + const char *merge_ranges_string = NULL;
> + apr_array_header_t *merge_rangelist;
> + svn_mergeinfo_inheritance_t inherit;
> + apr_hash_t *mergeinfo = apr_hash_make(pool);
> + svn_stringbuf_t *commit_rev_mergeinfo;
> +
> + SVN_ERR(svn_ra_svn_parse_tuple(params, pool, "ccrrcw", &merge_target,
> + &merge_source, &min_commit_rev,
> + &max_commit_rev, &merge_ranges_string,
> + &inherit_word));
> + inherit = svn_inheritance_from_word(inherit_word);
> +
> + /* Canonicalize the paths. */
> + merge_target = svn_path_canonicalize(merge_target, pool);
> + merge_source = svn_path_canonicalize(merge_source, pool);
> + {
> + /* We lack svn_rangelist_parse, so creating a dummy mergeinfo
> + and parse with the help of svn_mergeinfo_parse. */
> + apr_hash_t *dummy_mergeinfo;
> + char *dummy_mergeinfo_str = apr_pstrcat(pool, merge_source, ":",
> + merge_ranges_string, NULL);
> + SVN_ERR(svn_mergeinfo_parse(&dummy_mergeinfo, dummy_mergeinfo_str, pool));
> + merge_rangelist = apr_hash_get(dummy_mergeinfo, merge_source,
> + APR_HASH_KEY_STRING);
> + }
> +
> + SVN_ERR(trivial_auth_request(conn, pool, b));
> + SVN_CMD_ERR(svn_repos_get_commit_revs_for_merge_ranges(
> + &commit_rev_range_list,
> + b->repos, merge_target,
> + merge_source,
> + min_commit_rev,
> + max_commit_rev,
> + merge_rangelist,
> + inherit,
> + authz_check_access_cb_func(b),
> + b, pool));
> + apr_hash_set(mergeinfo, merge_source, APR_HASH_KEY_STRING,
> + commit_rev_range_list);
> + SVN_ERR(svn_mergeinfo_to_stringbuf(&commit_rev_mergeinfo, mergeinfo, pool));
> + SVN_ERR(svn_ra_svn_write_tuple(conn, pool, "w(c)", "success",
> + commit_rev_mergeinfo->data));
> + return SVN_NO_ERROR;
> +}
> /* Send a log entry to the client. */
> static svn_error_t *log_receiver(void *baton,
> svn_log_entry_t *log_entry,
> @@ -2401,6 +2457,7 @@
> { "get-locks", get_locks },
> { "replay", replay },
> { "replay-range", replay_range },
> + { "commit-revs-for-merge-ranges", get_commit_revs_for_merge_ranges},
> { NULL }
> };
>
>
> Modified: branches/issue-2897/subversion/tests/cmdline/merge_tests.py
> URL: http://svn.collab.net/viewvc/svn/branches/issue-2897/subversion/tests/cmdline/merge_tests.py?pathrev=27982&r1=27981&r2=27982
> ==============================================================================
> --- branches/issue-2897/subversion/tests/cmdline/merge_tests.py (original)
> +++ branches/issue-2897/subversion/tests/cmdline/merge_tests.py Thu Nov 22 11:35:07 2007
> @@ -9460,7 +9460,7 @@
> detect_copy_src_for_target_with_multiple_ancestors,
> prop_add_to_child_with_mergeinfo,
> diff_repos_does_not_update_mergeinfo,
> - XFail(avoid_reflected_revs),
> + avoid_reflected_revs,
> update_loses_mergeinfo,
> XFail(merge_loses_mergeinfo),
> single_file_replace_style_merge_capability,
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: svn-unsubscribe@subversion.tigris.org
> For additional commands, e-mail: svn-help@subversion.tigris.org
>
>
--
David Glasser | glasser_at_davidglasser.net | http://www.davidglasser.net/
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@subversion.tigris.org
For additional commands, e-mail: dev-help@subversion.tigris.org
Received on Tue Nov 27 14:50:58 2007