Author: hwright
Date: Sat Apr 14 16:59:26 2012
New Revision: 1326150
URL: http://svn.apache.org/viewvc?rev=1326150&view=rev
Log:
On the ev2-export branch:
Reimplement repos->repos copy in terms of repos relpaths.
Note: there are a few failing tests for 'cp --parents URL URL' due to a
pre-existing issue with not providing the proper children.
* subversion/libsvn_client/copy.c
(path_driver_info_t): Remove a member, and rename a few others.
(drive_single_path): Use pre-calculated values, rather than calculating
paths internally.
(repos_to_repos_copy): Use repos_relpaths throughout.
Modified:
subversion/branches/ev2-export/subversion/libsvn_client/copy.c
Modified: subversion/branches/ev2-export/subversion/libsvn_client/copy.c
URL:
http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/libsvn_client/copy.c?rev=1326150&r1=1326149&r2=1326150&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/libsvn_client/copy.c (original)
+++ subversion/branches/ev2-export/subversion/libsvn_client/copy.c Sat Apr 14
16:59:26 2012
@@ -37,6 +37,8 @@
#include "svn_time.h"
#include "svn_props.h"
#include "svn_mergeinfo.h"
+#include "svn_hash.h"
+#include "svn_sorts.h"
#include "svn_pools.h"
#include "client.h"
@@ -478,9 +480,8 @@ verify_wc_srcs_and_dsts(const apr_array_
/* Path-specific state used as part of path_driver_cb_baton. */
typedef struct path_driver_info_t
{
- const char *src_url;
- const char *src_path;
- const char *dst_path;
+ const char *src_relpath;
+ const char *dst_relpath;
svn_node_kind_t src_kind;
svn_revnum_t src_revnum;
svn_boolean_t resurrection;
@@ -571,7 +572,7 @@ find_absent_parents2(svn_ra_session_t *r
static svn_error_t *
drive_single_path(svn_editor_t *editor,
- const char *path,
+ const char *dst_relpath,
path_driver_info_t *path_info,
svn_boolean_t is_move,
const char *repos_root,
@@ -580,11 +581,6 @@ drive_single_path(svn_editor_t *editor,
apr_hash_t *props = apr_hash_make(scratch_pool);
svn_boolean_t do_delete = FALSE;
svn_boolean_t do_add = FALSE;
- const char *dst_relpath = svn_uri_skip_ancestor(repos_root, path,
- scratch_pool);
- const char *src_relpath = svn_uri_skip_ancestor(repos_root,
- path_info->src_url,
- scratch_pool);
/* If this is a resurrection, we know the source and dest paths are
the same, and that our driver will only be calling us once. */
@@ -601,7 +597,7 @@ drive_single_path(svn_editor_t *editor,
or the destination of the move. */
if (is_move)
{
- if (strcmp(src_relpath, dst_relpath) == 0)
+ if (strcmp(path_info->src_relpath, dst_relpath) == 0)
do_delete = TRUE;
else
do_add = TRUE;
@@ -628,7 +624,7 @@ drive_single_path(svn_editor_t *editor,
path_info->mergeinfo);
SVN_ERR(svn_editor_copy(editor,
- src_relpath, path_info->src_revnum,
+ path_info->src_relpath, path_info->src_revnum,
dst_relpath, SVN_INVALID_REVNUM));
if (path_info->src_kind == svn_node_file)
@@ -712,7 +708,6 @@ repos_to_repos_copy(const apr_array_head
apr_array_header_t *paths;
apr_hash_t *action_hash = apr_hash_make(pool);
apr_array_header_t *path_infos;
- const char *top_url, *top_url_all, *top_url_dst;
const char *message, *repos_root;
svn_ra_session_t *ra_session = NULL;
svn_editor_t *editor;
@@ -732,6 +727,10 @@ repos_to_repos_copy(const apr_array_head
ctx, pool));
SVN_ERR(svn_ra_get_repos_root2(ra_session, &repos_root, pool));
+ /* We're going to reparent the session to the repos_root, and then drive
+ the Ev2 from there. This might have issue #3242 implications. */
+ SVN_ERR(svn_ra_reparent(ra_session, repos_root, pool));
+
/* Verify that sources and destinations are all at or under
REPOS_ROOT. While here, create a path_info struct for each
src/dst pair and initialize portions of it with normalized source
@@ -755,6 +754,7 @@ repos_to_repos_copy(const apr_array_head
/* Run the history function to get the source's URL and revnum in the
operational revision. */
+ /* ### Gah! We have to wrap this call in a reparent... */
SVN_ERR(svn_ra_reparent(ra_session, pair->src_abspath_or_url, pool));
SVN_ERR(svn_client__repos_locations(&pair->src_abspath_or_url,
&pair->src_revnum,
@@ -764,9 +764,9 @@ repos_to_repos_copy(const apr_array_head
&pair->src_peg_revision,
&pair->src_op_revision, NULL,
ctx, pool));
+ SVN_ERR(svn_ra_reparent(ra_session, repos_root, pool));
/* Go ahead and grab mergeinfo from the source, too. */
- SVN_ERR(svn_ra_reparent(ra_session, pair->src_abspath_or_url, pool));
SVN_ERR(svn_client__get_repos_mergeinfo(
&mergeinfo, ra_session,
pair->src_abspath_or_url, pair->src_revnum,
@@ -775,24 +775,17 @@ repos_to_repos_copy(const apr_array_head
SVN_ERR(svn_mergeinfo_to_string(&info->mergeinfo, mergeinfo, pool));
/* Plop an INFO structure onto our array thereof. */
- info->src_url = pair->src_abspath_or_url;
+ info->src_relpath = svn_uri_skip_ancestor(repos_root,
+ pair->src_abspath_or_url,
+ pool);
+ info->dst_relpath = svn_uri_skip_ancestor(repos_root,
+ pair->dst_abspath_or_url,
+ pool);
info->src_revnum = pair->src_revnum;
info->resurrection = FALSE;
APR_ARRAY_PUSH(path_infos, path_driver_info_t *) = info;
}
- /* If this is a move, we have to open our session to the longest
- path common to all SRC_URLS and DST_URLS in the repository so we
- can do existence checks on all paths, and so we can operate on
- all paths in the case of a move. But if this is *not* a move,
- then opening our session at the longest path common to sources
- *and* destinations might be an optimization when the user is
- authorized to access all that stuff, but could cause the
- operation to fail altogether otherwise. See issue #3242. */
- SVN_ERR(get_copy_pair_ancestors(copy_pairs, NULL, &top_url_dst, &top_url_all,
- pool));
- top_url = is_move ? top_url_all : top_url_dst;
-
/* Check each src/dst pair for resurrection, and verify that TOP_URL
is anchored high enough to cover all the editor_t activities
required for this operation. */
@@ -806,95 +799,29 @@ repos_to_repos_copy(const apr_array_head
/* Source and destination are the same? It's a resurrection. */
if (strcmp(pair->src_abspath_or_url, pair->dst_abspath_or_url) == 0)
info->resurrection = TRUE;
-
- /* We need to add each dst_URL, and (in a move) we'll need to
- delete each src_URL. Our selection of TOP_URL so far ensures
- that all our destination URLs (and source URLs, for moves)
- are at least as deep as TOP_URL, but we need to make sure
- that TOP_URL is an *ancestor* of all our to-be-edited paths.
-
- Issue #683 is demonstrates this scenario. If you're
- resurrecting a deleted item like this: 'svn cp -rN src_URL
- dst_URL', then src_URL == dst_URL == top_url. In this
- situation, we want to open an RA session to be at least the
- *parent* of all three. */
- if ((strcmp(top_url, pair->dst_abspath_or_url) == 0)
- && (strcmp(top_url, repos_root) != 0))
- {
- top_url = svn_uri_dirname(top_url, pool);
- }
- if (is_move
- && (strcmp(top_url, pair->src_abspath_or_url) == 0)
- && (strcmp(top_url, repos_root) != 0))
- {
- top_url = svn_uri_dirname(top_url, pool);
- }
}
- /* Point the RA session to our current TOP_URL. */
- SVN_ERR(svn_ra_reparent(ra_session, top_url, pool));
-
/* If we're allowed to create nonexistent parent directories of our
destinations, then make a list in NEW_DIRS of the parent
directories of the destination that don't yet exist. */
if (make_parents)
{
+ path_driver_info_t *info = APR_ARRAY_IDX(path_infos, 0,
+ path_driver_info_t *);
+
new_dirs = apr_array_make(pool, 0, sizeof(const char *));
- /* If this is a move, TOP_URL is at least the common ancestor of
- all the paths (sources and destinations) involved. Assuming
- the sources exist (which is fair, because if they don't, this
- whole operation will fail anyway), TOP_URL must also exist.
- So it's the paths between TOP_URL and the destinations which
- we have to check for existence. But here, we take advantage
- of the knowledge of our caller. We know that if there are
- multiple copy/move operations being requested, then the
+ /* We take advantage of the knowledge of our caller. We know that
+ if there are multiple copy/move operations being requested, then the
destinations of the copies/moves will all be siblings of one
another. Therefore, we need only to check for the
nonexistent paths between TOP_URL and *one* of our
destinations to find nonexistent parents of all of them. */
- if (is_move)
- {
- /* Imagine a situation where the user tries to copy an
- existing source directory to nonexistent directory with
- --parents options specified:
-
- svn copy --parents URL/src URL/dst
-
- where src exists and dst does not. If the dirname of the
- destination path is equal to TOP_URL,
- do not try to add dst to the NEW_DIRS list since it
- will be added to the commit items array later in this
- function. */
- const char *dir = svn_uri_skip_ancestor(
- top_url,
- svn_uri_dirname(first_pair->dst_abspath_or_url,
- pool),
- pool);
- if (dir && *dir)
- SVN_ERR(find_absent_parents1(ra_session, dir, new_dirs, pool));
- }
- /* If, however, this is *not* a move, TOP_URL only points to the
- common ancestor of our destination path(s), or possibly one
- level higher. We'll need to do an existence crawl toward the
- root of the repository, starting with one of our destinations
- (see "... take advantage of the knowledge of our caller ..."
- above), and possibly adjusting TOP_URL as we go. */
- else
- {
- apr_array_header_t *new_urls =
- apr_array_make(pool, 0, sizeof(const char *));
- SVN_ERR(find_absent_parents2(ra_session, &top_url, new_urls, pool));
-
- /* Convert absolute URLs into relpaths relative to TOP_URL. */
- for (i = 0; i < new_urls->nelts; i++)
- {
- const char *new_url = APR_ARRAY_IDX(new_urls, i, const char *);
- const char *dir = svn_uri_skip_ancestor(top_url, new_url, pool);
+ SVN_ERR(find_absent_parents1(ra_session, info->dst_relpath, new_dirs,
+ pool));
- APR_ARRAY_PUSH(new_dirs, const char *) = dir;
- }
- }
+ qsort(new_dirs->elts, new_dirs->nelts, new_dirs->elt_size,
+ svn_sort_compare_paths);
}
/* For each src/dst pair, check to see if that SRC_URL is a child of
@@ -916,8 +843,6 @@ repos_to_repos_copy(const apr_array_head
&& (relpath != NULL && *relpath != '\0'))
{
info->resurrection = TRUE;
- top_url = svn_uri_dirname(top_url, pool);
- SVN_ERR(svn_ra_reparent(ra_session, top_url, pool));
}
}
@@ -935,28 +860,10 @@ repos_to_repos_copy(const apr_array_head
path_driver_info_t *info =
APR_ARRAY_IDX(path_infos, i, path_driver_info_t *);
svn_node_kind_t dst_kind;
- const char *src_rel, *dst_rel;
- src_rel = svn_uri_skip_ancestor(top_url, pair->src_abspath_or_url, pool);
- if (src_rel)
- {
- SVN_ERR(svn_ra_check_path(ra_session, src_rel, pair->src_revnum,
- &info->src_kind, pool));
- }
- else
- {
- const char *old_url;
-
- src_rel = NULL;
- SVN_ERR_ASSERT(! is_move);
+ SVN_ERR(svn_ra_check_path(ra_session, info->src_relpath,
+ pair->src_revnum, &info->src_kind, pool));
- SVN_ERR(svn_client__ensure_ra_session_url(&old_url, ra_session,
- pair->src_abspath_or_url,
- pool));
- SVN_ERR(svn_ra_check_path(ra_session, "", pair->src_revnum,
- &info->src_kind, pool));
- SVN_ERR(svn_ra_reparent(ra_session, old_url, pool));
- }
if (info->src_kind == svn_node_none)
return svn_error_createf(SVN_ERR_FS_NOT_FOUND, NULL,
_("Path '%s' does not exist in revision %ld"),
@@ -964,24 +871,17 @@ repos_to_repos_copy(const apr_array_head
/* Figure out the basename that will result from this operation,
and ensure that we aren't trying to overwrite existing paths. */
- dst_rel = svn_uri_skip_ancestor(top_url, pair->dst_abspath_or_url, pool);
- SVN_ERR(svn_ra_check_path(ra_session, dst_rel, SVN_INVALID_REVNUM,
- &dst_kind, pool));
+ SVN_ERR(svn_ra_check_path(ra_session, info->dst_relpath,
+ SVN_INVALID_REVNUM, &dst_kind, pool));
if (dst_kind != svn_node_none)
return svn_error_createf(SVN_ERR_FS_ALREADY_EXISTS, NULL,
- _("Path '%s' already exists"), dst_rel);
+ _("Path '%s' already exists"),
+ info->dst_relpath);
- /* More info for our INFO structure. */
- info->src_path = src_rel;
- info->dst_path = dst_rel;
-
- apr_hash_set(action_hash, svn_path_url_add_component2(
- top_url, info->dst_path, pool),
- APR_HASH_KEY_STRING, info);
+ apr_hash_set(action_hash, info->dst_relpath, APR_HASH_KEY_STRING, info);
if (is_move && (! info->resurrection))
- apr_hash_set(action_hash, svn_path_url_add_component2(
- top_url, info->src_path, pool),
- APR_HASH_KEY_STRING, info);
+ apr_hash_set(action_hash, info->src_relpath, APR_HASH_KEY_STRING,
+ info);
}
if (SVN_CLIENT__HAS_LOG_MSG_FUNC(ctx))
@@ -1001,7 +901,8 @@ repos_to_repos_copy(const apr_array_head
const char *relpath = APR_ARRAY_IDX(new_dirs, i, const char *);
item = svn_client_commit_item3_create(pool);
- item->url = svn_path_url_add_component2(top_url, relpath, pool);
+ item->url = svn_path_url_add_component2(repos_root, relpath,
+ pool);
item->state_flags = SVN_CLIENT_COMMIT_ITEM_ADD;
APR_ARRAY_PUSH(commit_items, svn_client_commit_item3_t *) = item;
}
@@ -1013,16 +914,16 @@ repos_to_repos_copy(const apr_array_head
path_driver_info_t *);
item = svn_client_commit_item3_create(pool);
- item->url = svn_path_url_add_component2(top_url, info->dst_path,
- pool);
+ item->url = svn_path_url_add_component2(repos_root,
+ info->dst_relpath, pool);
item->state_flags = SVN_CLIENT_COMMIT_ITEM_ADD;
APR_ARRAY_PUSH(commit_items, svn_client_commit_item3_t *) = item;
if (is_move && (! info->resurrection))
{
item = apr_pcalloc(pool, sizeof(*item));
- item->url = svn_path_url_add_component2(top_url, info->src_path,
- pool);
+ item->url = svn_path_url_add_component2(repos_root,
+ info->src_relpath, pool);
item->state_flags = SVN_CLIENT_COMMIT_ITEM_DELETE;
APR_ARRAY_PUSH(commit_items, svn_client_commit_item3_t *) = item;
}
@@ -1043,14 +944,12 @@ repos_to_repos_copy(const apr_array_head
path_driver_info_t *info = APR_ARRAY_IDX(path_infos, i,
path_driver_info_t *);
- SVN_ERR(svn_path_check_valid(info->dst_path, pool));
- APR_ARRAY_PUSH(paths, const char *) = svn_path_url_add_component2(
- top_url, info->dst_path, pool);
+ SVN_ERR(svn_path_check_valid(info->dst_relpath, pool));
+ APR_ARRAY_PUSH(paths, const char *) = info->dst_relpath;
if (is_move && (! info->resurrection))
{
- SVN_ERR(svn_path_check_valid(info->src_path, pool));
- APR_ARRAY_PUSH(paths, const char *) = svn_path_url_add_component2(
- top_url, info->src_path, pool);
+ SVN_ERR(svn_path_check_valid(info->src_relpath, pool));
+ APR_ARRAY_PUSH(paths, const char *) = info->src_relpath;
}
}