Index: subversion/libsvn_client/client.h =================================================================== --- subversion/libsvn_client/client.h (revision 27779) +++ subversion/libsvn_client/client.h (working copy) @@ -24,6 +24,7 @@ #include #include "svn_types.h" +#include "svn_opt.h" #include "svn_string.h" #include "svn_error.h" #include "svn_ra.h" @@ -34,6 +35,34 @@ #endif /* __cplusplus */ + +/* Set *URL and *PEG_REVNUM (the latter is ignored if NULL) to the + repository URL of PATH_OR_URL. If PATH_OR_URL is a WC path and + PEG_REVISION->kind is svn_opt_revision_working, use the + corresponding entry's copyfrom info. RA_SESSION and ADM_ACCESS may + be NULL, regardless of whether PATH_OR_URL is a URL. Use CTX for + cancellation (ignored if NULL), and POOL for all allocations. */ +svn_error_t * +svn_client__derive_location(const char **url, + svn_revnum_t *peg_revnum, + const char *path_or_url, + const svn_opt_revision_t *peg_revision, + const svn_ra_session_t *ra_session, + svn_wc_adm_access_t *adm_access, + svn_client_ctx_t *ctx, + apr_pool_t *pool); + +/* Get the repository URL and revision number for WC entry ENTRY, + which is sometimes the entry's copyfrom info rather than its actual + URL and revision. */ +svn_error_t * +svn_client__entry_location(const char **url, + svn_revnum_t *revnum, + const char *path_or_url, + enum svn_opt_revision_kind peg_rev_kind, + const svn_wc_entry_t *entry, + apr_pool_t *pool); + /* Set *REVNUM to the revision number identified by REVISION. If REVISION->kind is svn_opt_revision_number, just use Index: subversion/libsvn_client/url.c =================================================================== --- subversion/libsvn_client/url.c (revision 27779) +++ subversion/libsvn_client/url.c (working copy) @@ -2,7 +2,7 @@ * url.c: converting paths to urls * * ==================================================================== - * Copyright (c) 2000-2004 CollabNet. All rights reserved. + * Copyright (c) 2000-2007 CollabNet. All rights reserved. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -21,12 +21,16 @@ #include #include "svn_error.h" +#include "svn_types.h" +#include "svn_opt.h" #include "svn_wc.h" #include "svn_client.h" #include "svn_path.h" + +#include "private/svn_wc_private.h" #include "client.h" +#include "svn_private_config.h" - svn_error_t * @@ -34,25 +38,10 @@ const char *path_or_url, apr_pool_t *pool) { - svn_wc_adm_access_t *adm_access; - const svn_wc_entry_t *entry; - svn_boolean_t is_url = svn_path_is_url(path_or_url); - - if (is_url) - { - *url = path_or_url; - } - else - { - SVN_ERR(svn_wc_adm_probe_open3(&adm_access, NULL, path_or_url, - FALSE, 0, NULL, NULL, pool)); - SVN_ERR(svn_wc_entry(&entry, path_or_url, adm_access, FALSE, pool)); - SVN_ERR(svn_wc_adm_close(adm_access)); - - *url = entry ? entry->url : NULL; - } - - return SVN_NO_ERROR; + svn_opt_revision_t revision; + revision.kind = svn_opt_revision_unspecified; + return svn_client__derive_location(url, NULL, path_or_url, &revision, + NULL, NULL, NULL, pool); } @@ -68,3 +57,103 @@ return svn_client__get_repos_root(url, path_or_url, &peg_revision, NULL, ctx, pool); } + +svn_error_t * +svn_client__derive_location(const char **url, + svn_revnum_t *peg_revnum, + const char *path_or_url, + const svn_opt_revision_t *peg_revision, + const svn_ra_session_t *ra_session, + svn_wc_adm_access_t *adm_access, + svn_client_ctx_t *ctx, + apr_pool_t *pool) +{ + /* If PATH_OR_URL is a local path (not a URL), we need to transform + it into a URL. */ + if (! svn_path_is_url(path_or_url)) + { + const svn_wc_entry_t *entry; + + if (adm_access) + { + SVN_ERR(svn_wc__entry_versioned(&entry, path_or_url, adm_access, + FALSE, pool)); + } + else + { + svn_cancel_func_t cancel_func; + void *cancel_baton; + + if (ctx) + { + cancel_func = ctx->cancel_func; + cancel_baton = ctx->cancel_baton; + } + + SVN_ERR(svn_wc_adm_probe_open3(&adm_access, NULL, path_or_url, + FALSE, 0, cancel_func, cancel_baton, + pool)); + SVN_ERR(svn_wc__entry_versioned(&entry, path_or_url, adm_access, + FALSE, pool)); + SVN_ERR(svn_wc_adm_close(adm_access)); + } + + SVN_ERR(svn_client__entry_location(url, peg_revnum, path_or_url, + peg_revision->kind, entry, pool)); + } + else + { + *url = path_or_url; + /* peg_revnum will be set below. */ + } + + /* If we haven't resolved for ourselves a numeric peg revision, do so. */ + if (! SVN_IS_VALID_REVNUM(peg_revnum)) + { + /* Use sesspool to assure that if we opened an RA session, we + close it. */ + apr_pool_t *sesspool = NULL; + svn_ra_session_t *session = ra_session; + if (session == NULL) + { + sesspool = svn_pool_create(pool); + SVN_ERR(svn_client__open_ra_session_internal(&session, *url, NULL, + NULL, NULL, FALSE, + TRUE, ctx, sesspool)); + } + SVN_ERR(svn_client__get_revision_number(&peg_revnum, NULL, session, + peg_revision, NULL, pool)); + if (sesspool) + svn_pool_destroy(sesspool); + } + + return SVN_NO_ERROR; +} + +svn_error_t * +svn_client__entry_location(const char **url, svn_revnum_t *revnum, + const char *wc_path, + enum svn_opt_revision_kind peg_rev_kind, + const svn_wc_entry_t *entry, apr_pool_t *pool) +{ + if (entry->copyfrom_url && peg_rev_kind == svn_opt_revision_working) + { + *url = entry->copyfrom_url; + if (revnum) + *revnum = entry->copyfrom_rev; + } + else if (entry->url) + { + *url = entry->url; + if (revnum) + *revnum = entry->revision; + } + else + { + return svn_error_createf(SVN_ERR_ENTRY_MISSING_URL, NULL, + _("Entry for '%s' has no URL"), + svn_path_local_style(wc_path, pool)); + } + + return SVN_NO_ERROR; +} Index: subversion/libsvn_client/copy.c =================================================================== --- subversion/libsvn_client/copy.c (revision 27779) +++ subversion/libsvn_client/copy.c (working copy) @@ -147,7 +147,10 @@ } else { - svn_client__derive_mergeinfo_location(&src_url, &src_revnum, entry); + SVN_ERR(svn_client__entry_location(&src_url, &src_revnum, + src_path_or_url, + svn_opt_revision_working, entry, + pool)); } } else Index: subversion/libsvn_client/mergeinfo.c =================================================================== --- subversion/libsvn_client/mergeinfo.c (revision 27779) +++ subversion/libsvn_client/mergeinfo.c (working copy) @@ -90,36 +90,6 @@ adm_access, TRUE /* skip checks */, pool); } -void -svn_client__derive_mergeinfo_location(const char **url, - svn_revnum_t *rev, - const svn_wc_entry_t *entry) -{ - /* ### FIXME: dionisos sez: "We can have schedule 'normal' files - ### with a copied parameter of TRUE and a revision number of - ### INVALID_REVNUM. Copied directories cause this behaviour on - ### their children. It's an implementation shortcut to model - ### wc-side copies." */ - switch (entry->schedule) - { - case svn_wc_schedule_add: - case svn_wc_schedule_replace: - /* If we have any history, consider its mergeinfo. */ - if (entry->copyfrom_url) - { - *url = entry->copyfrom_url; - *rev = entry->copyfrom_rev; - break; - } - - default: - /* Consider the mergeinfo for the WC target. */ - *url = entry->url; - *rev = entry->revision; - break; - } -} - /*-----------------------------------------------------------------------*/ /*** Retrieving mergeinfo. ***/ @@ -335,13 +305,9 @@ parent if TARGET_WCPATH is missing. These limited entries do not have a URL and without that we cannot get accurate mergeinfo for TARGET_WCPATH. */ - if (entry->url == NULL) - return svn_error_createf(SVN_ERR_ENTRY_MISSING_URL, NULL, - _("Entry '%s' has no URL"), - svn_path_local_style(target_wcpath, pool)); + SVN_ERR(svn_client__entry_location(&url, &target_rev, target_wcpath, + svn_opt_revision_working, entry, pool)); - svn_client__derive_mergeinfo_location(&url, &target_rev, entry); - repos_rel_path = url + strlen(entry->repos); if (repos_only) @@ -407,10 +373,10 @@ { 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 */ + svn_ra_session_t *session = ra_session; int i; /* If PATH_OR_URL is a local path (not a URL), we need to transform @@ -418,60 +384,18 @@ 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; + SVN_ERR(svn_client__derive_location(&url, &peg_revnum, path_or_url, + peg_revision, session, adm_access, + ctx, pool)); - 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 + if (session == NULL) { - url = path_or_url; - } - - /* 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)); + 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, Index: subversion/libsvn_client/mergeinfo.h =================================================================== --- subversion/libsvn_client/mergeinfo.h (revision 27779) +++ subversion/libsvn_client/mergeinfo.h (working copy) @@ -226,13 +226,5 @@ svn_client_ctx_t *ctx, apr_pool_t *pool); -/* Get the repository URL and revision number for which to request - mergeinfo for a WC entry, which sometimes needs to be the entry's - copyfrom info rather than its actual URL and revision. */ -void -svn_client__derive_mergeinfo_location(const char **url, - svn_revnum_t *rev, - const svn_wc_entry_t *entry); - #endif /* SVN_LIBSVN_CLIENT_MERGEINFO_H */