On Thu, 08 Nov 2007, cmpilato@tigris.org wrote:
...
> New client library helper function, svn_client__get_implicit_mergeinfo().
>
> * subversion/libsvn_client/mergeinfo.h,
> * subversion/libsvn_client/mergeinfo.c
> (svn_client__get_implicit_mergeinfo): New function.
>
> Modified:
> trunk/subversion/libsvn_client/mergeinfo.c
> trunk/subversion/libsvn_client/mergeinfo.h
>
> Modified: trunk/subversion/libsvn_client/mergeinfo.c
> URL: http://svn.collab.net/viewvc/svn/trunk/subversion/libsvn_client/mergeinfo.c?pathrev=27710&r1=27709&r2=27710
> ==============================================================================
> --- trunk/subversion/libsvn_client/mergeinfo.c (original)
> +++ trunk/subversion/libsvn_client/mergeinfo.c Thu Nov 8 07:25:48 2007
> @@ -400,6 +400,129 @@
> return SVN_NO_ERROR;
> }
>
> +
> +svn_error_t *
> +svn_client__get_implicit_mergeinfo(apr_hash_t **mergeinfo_p,
> + const char *path_or_url,
> + const svn_opt_revision_t *peg_revision,
> + svn_ra_session_t *ra_session,
> + svn_wc_adm_access_t *adm_access,
> + svn_client_ctx_t *ctx,
> + apr_pool_t *pool)
> +{
> + apr_array_header_t *segments;
> + svn_revnum_t peg_revnum = SVN_INVALID_REVNUM;
> + svn_ra_session_t *session = ra_session;
> + const char *url;
> + apr_hash_t *mergeinfo = apr_hash_make(pool);
> + apr_pool_t *sesspool = NULL; /* only used for an RA session we open */
> + int i;
> +
> + /* If PATH_OR_URL is a local path (not a URL), we need to transform
> + it into a URL, open an RA session for it, and resolve the peg
> + revision. Note that if the local item is scheduled for addition
> + as a copy of something else, we'll use its copyfrom data to query
> + its history. */
> + if (! svn_path_is_url(path_or_url))
> + {
> + const svn_wc_entry_t *entry;
> +
> + ra_session = NULL;
> + if (adm_access)
> + {
> + SVN_ERR(svn_wc_entry(&entry, path_or_url, adm_access, FALSE, pool));
> + }
> + else
> + {
> + SVN_ERR(svn_wc_adm_probe_open3(&adm_access, NULL, path_or_url,
> + FALSE, 0, ctx->cancel_func,
> + ctx->cancel_baton, pool));
> + SVN_ERR(svn_wc_entry(&entry, path_or_url, adm_access, FALSE, pool));
> + SVN_ERR(svn_wc_adm_close(adm_access));
> + }
> +
> + if (entry->copyfrom_url
> + && peg_revision->kind == svn_opt_revision_working)
> + {
> + url = entry->copyfrom_url;
> + peg_revnum = entry->copyfrom_rev;
> + }
> + else if (entry->url)
> + {
> + url = entry->url;
> + }
> + else
> + {
> + return svn_error_createf(SVN_ERR_ENTRY_MISSING_URL, NULL,
> + _("'%s' has no URL"),
> + svn_path_local_style(path_or_url, pool));
> + }
> + }
> + else
> + {
> + url = path_or_url;
> + }
I feel like I've written the above code ten times. I can't put my
finger on exactly what it should look like, but I get the feeling we
should be using a shared routine for this...
How about something like:
/* Set *URL to the repository URL of PATH_OR_URL. ADM_ACCESS may be
NULL, if PATH_OR_URL is a URL. Use POOL for all allocations. */
svn_error_t *
svn_client__derive_url(const char **url,
const char *path_or_url,
svn_wc_adm_access_t *adm_access,
apr_pool_t *pool);
> +
> + /* If we have no RA session yet, open one. */
> + if (! session)
> + {
> + sesspool = svn_pool_create(pool);
> + SVN_ERR(svn_client__open_ra_session_internal(&session, url,
> + NULL, NULL, NULL, FALSE,
> + TRUE, ctx, sesspool));
> + }
> +
> + /* If we haven't resolved for ourselves a numeric peg revision, do so. */
> + if (! SVN_IS_VALID_REVNUM(peg_revnum))
> + SVN_ERR(svn_client__get_revision_number(&peg_revnum, NULL, session,
> + peg_revision, NULL, pool));
> +
> + /* Fetch the location segments for our URL@PEG_REVNUM. */
> + SVN_ERR(svn_client__repos_location_segments(&segments, session, "",
> + peg_revnum, peg_revnum, 0,
> + ctx, pool));
> +
> + /* Translate location segments into merge sources and ranges. */
> + for (i = 0; i < segments->nelts; i++)
> + {
> + svn_location_segment_t *segment =
> + APR_ARRAY_IDX(segments, i, svn_location_segment_t *);
> + apr_array_header_t *path_ranges;
> + svn_merge_range_t *range;
> + const char *source_path;
> +
> + /* No path segment? Skip it. */
> + if (! segment->path)
> + continue;
> +
> + /* Prepend a leading slash to our path. */
> + source_path = apr_pstrcat(pool, "/", segment->path, NULL);
> +
> + /* See if we already stored ranges for this path. If not, make
> + a new list. */
> + path_ranges = apr_hash_get(mergeinfo, source_path, APR_HASH_KEY_STRING);
> + if (! path_ranges)
> + path_ranges = apr_array_make(pool, 1, sizeof(range));
> +
> + /* Build a merge range, push it onto the list of ranges, and for
> + good measure, (re)store it in the hash. */
> + range = apr_pcalloc(pool, sizeof(*range));
> + range->start = MAX(segment->range_start - 1, 0);
> + range->end = segment->range_end;
> + range->inheritable = TRUE;
> + APR_ARRAY_PUSH(path_ranges, svn_merge_range_t *) = range;
> + apr_hash_set(mergeinfo, source_path, APR_HASH_KEY_STRING, path_ranges);
> + }
> +
> + /* If we opened an RA session, ensure its closure. */
> + if (sesspool)
> + svn_pool_destroy(sesspool);
> +
> + *mergeinfo_p = mergeinfo;
> + return SVN_NO_ERROR;
> +}
The remaining part of this function definitely has some overlap with
code I've seen or written in libsvn_client's copy.c, merge.c, and/or
mergeinfo.c.
- application/pgp-signature attachment: stored
Received on Mon Nov 12 19:18:09 2007