Modified: subversion/branches/revprop-packing/subversion/libsvn_client/commit_util.c URL: http://svn.apache.org/viewvc/subversion/branches/revprop-packing/subversion/libsvn_client/commit_util.c?rev=1231318&r1=1231317&r2=1231318&view=diff ============================================================================== --- subversion/branches/revprop-packing/subversion/libsvn_client/commit_util.c (original) +++ subversion/branches/revprop-packing/subversion/libsvn_client/commit_util.c Fri Jan 13 21:40:26 2012 @@ -410,6 +410,12 @@ bail_on_tree_conflicted_ancestor(svn_wc_ when harvesting committables; that is, don't add a path to COMMITTABLES unless it's a member of one of those changelists. + IS_EXPLICIT_TARGET should always be passed as TRUE, except when + harvest_committables() calls itself in recursion. This provides a way to + tell whether LOCAL_ABSPATH was an original target or whether it was reached + by recursing deeper into a dir target. (This is used to skip all file + externals that aren't explicit commit targets.) + If CANCEL_FUNC is non-null, call it with CANCEL_BATON to see if the user has cancelled the operation. @@ -428,6 +434,7 @@ harvest_committables(svn_wc_context_t *w apr_hash_t *changelists, svn_boolean_t skip_files, svn_boolean_t skip_dirs, + svn_boolean_t is_explicit_target, svn_client__check_url_kind_t check_url_func, void *check_url_baton, svn_cancel_func_t cancel_func, @@ -543,10 +550,24 @@ harvest_committables(svn_wc_context_t *w svn_dirent_local_style(local_abspath, scratch_pool)); } - /* ### in need of comment */ - if (copy_mode - && is_update_root - && db_kind == svn_node_file) + /* Handle file externals. + * (IS_UPDATE_ROOT is more generally defined, but at the moment this + * condition matches only file externals.) + * + * Don't copy files that svn:externals brought into the WC. So in copy_mode, + * even explicit targets are skipped. + * + * Exclude file externals from recursion. Hande file externals only when + * passed as explicit target. Note that svn_client_commit6() passes all + * committable externals in as explicit targets iff they count. + * + * Also note that dir externals will never be reached recursively by this + * function, since svn_wc__node_get_children_of_working_node() (used below + * to recurse) does not return switched subdirs. */ + if (is_update_root + && db_kind == svn_node_file + && (copy_mode + || ! is_explicit_target)) { return SVN_NO_ERROR; } @@ -606,7 +627,7 @@ harvest_committables(svn_wc_context_t *w /* Determine from what parent we would be the deleted child */ SVN_ERR(svn_wc__node_get_origin(NULL, &revision, &repos_relpath, - NULL, NULL, wc_ctx, + NULL, NULL, NULL, wc_ctx, svn_dirent_dirname(local_abspath, scratch_pool), FALSE, scratch_pool, scratch_pool)); @@ -663,7 +684,7 @@ harvest_committables(svn_wc_context_t *w SVN_ERR(svn_wc__node_get_origin(NULL, &cf_rev, &cf_relpath, NULL, - NULL, + NULL, NULL, wc_ctx, local_abspath, FALSE, scratch_pool, scratch_pool)); @@ -841,6 +862,7 @@ harvest_committables(svn_wc_context_t *w changelists, (depth < svn_depth_files), (depth < svn_depth_immediates), + FALSE, /* IS_EXPLICIT_TARGET */ check_url_func, check_url_baton, cancel_func, cancel_baton, notify_func, notify_baton, @@ -1010,13 +1032,13 @@ svn_client__harvest_committables(svn_cli * Since we don't know what's included in the commit until we've * harvested all the targets, we can't reliably check this as we * go. So in `danglers', we record named targets whose parents - * are unversioned, then after harvesting the total commit group, we - * check to make sure those parents are included. + * do not yet exist in the repository. Then after harvesting the total + * commit group, we check to make sure those parents are included. * - * Each key of danglers is an unversioned parent. The (const char *) - * value is one of that parent's children which is named as part of - * the commit; the child is included only to make a better error - * message. + * Each key of danglers is a parent which does not exist in the + * repository. The (const char *) value is one of that parent's + * children which is named as part of the commit; the child is + * included only to make a better error message. * * (The reason we don't bother to check unnamed -- i.e, implicit -- * targets is that they can only join the commit if their parents @@ -1100,6 +1122,22 @@ svn_client__harvest_committables(svn_cli if (is_added) { + svn_boolean_t is_copy; + const char *copy_root_abspath; + + /* Copies are always committed recursively as long as the + * copy root is in the commit target list. + * So for nodes copied along with a parent, the copy root path + * is the dangling parent. See issue #4059. */ + SVN_ERR(svn_wc__node_get_origin(&is_copy, + NULL, NULL, NULL, NULL, + ©_root_abspath, + ctx->wc_ctx, + target_abspath, + FALSE, iterpool, iterpool)); + if (is_copy && strcmp(copy_root_abspath, target_abspath) != 0) + parent_abspath = copy_root_abspath; + /* Copy the parent and target into pool; iterpool lasts only for this loop iteration, and we check danglers after the loop is over. */ @@ -1125,6 +1163,7 @@ svn_client__harvest_committables(svn_cli FALSE /* COPY_MODE_ROOT */, depth, just_locked, changelist_hash, FALSE, FALSE, + TRUE /* IS_EXPLICIT_TARGET */, check_url_func, check_url_baton, ctx->cancel_func, ctx->cancel_baton, ctx->notify_func2, ctx->notify_baton2, @@ -1147,31 +1186,31 @@ svn_client__harvest_committables(svn_cli svn_pool_clear(iterpool); - if (! look_up_committable(*committables, dangling_parent, iterpool)) - { - const char *dangling_child = svn__apr_hash_index_val(hi); - - if (ctx->notify_func2 != NULL) - { - svn_wc_notify_t *notify; - - notify = svn_wc_create_notify(dangling_child, - svn_wc_notify_failed_no_parent, - scratch_pool); - - ctx->notify_func2(ctx->notify_baton2, notify, iterpool); - } - - return svn_error_createf( - SVN_ERR_ILLEGAL_TARGET, NULL, - _("'%s' is not under version control " - "and is not part of the commit, " - "yet its child '%s' is part of the commit"), - /* Probably one or both of these is an entry, but - safest to local_stylize just in case. */ - svn_dirent_local_style(dangling_parent, iterpool), - svn_dirent_local_style(dangling_child, iterpool)); - } + if (! look_up_committable(*committables, dangling_parent, iterpool)) + { + const char *dangling_child = svn__apr_hash_index_val(hi); + + if (ctx->notify_func2 != NULL) + { + svn_wc_notify_t *notify; + + notify = svn_wc_create_notify(dangling_child, + svn_wc_notify_failed_no_parent, + scratch_pool); + + ctx->notify_func2(ctx->notify_baton2, notify, iterpool); + } + + return svn_error_createf( + SVN_ERR_ILLEGAL_TARGET, NULL, + _("'%s' is not known to exist in the repository " + "and is not part of the commit, " + "yet its child '%s' is part of the commit"), + /* Probably one or both of these is an entry, but + safest to local_stylize just in case. */ + svn_dirent_local_style(dangling_parent, iterpool), + svn_dirent_local_style(dangling_child, iterpool)); + } } svn_pool_destroy(iterpool); @@ -1218,6 +1257,7 @@ harvest_copy_committables(void *baton, v FALSE, /* JUST_LOCKED */ NULL, FALSE, FALSE, /* skip files, dirs */ + TRUE, /* IS_EXPLICIT_TARGET (don't care) */ btn->check_url_func, btn->check_url_baton, btn->ctx->cancel_func, @@ -1341,14 +1381,9 @@ svn_client__condense_commit_items(const { svn_client_commit_item3_t *this_item = APR_ARRAY_IDX(ci, i, svn_client_commit_item3_t *); - size_t url_len = strlen(this_item->url); - size_t base_url_len = strlen(*base_url); - if (url_len > base_url_len) - this_item->session_relpath = svn_uri__is_child(*base_url, - this_item->url, pool); - else - this_item->session_relpath = ""; + this_item->session_relpath = svn_uri_skip_ancestor(*base_url, + this_item->url, pool); } #ifdef SVN_CLIENT_COMMIT_DEBUG /* ### TEMPORARY CODE ### */
Modified: subversion/branches/revprop-packing/subversion/libsvn_client/copy.c URL: http://svn.apache.org/viewvc/subversion/branches/revprop-packing/subversion/libsvn_client/copy.c?rev=1231318&r1=1231317&r2=1231318&view=diff ============================================================================== --- subversion/branches/revprop-packing/subversion/libsvn_client/copy.c (original) +++ subversion/branches/revprop-packing/subversion/libsvn_client/copy.c Fri Jan 13 21:40:26 2012 @@ -98,7 +98,7 @@ calculate_target_mergeinfo(svn_ra_sessio SVN_ERR(svn_wc__node_get_origin(NULL, &src_revnum, &repos_relpath, &repos_root_url, - NULL, + NULL, NULL, ctx->wc_ctx, local_abspath, FALSE, pool, pool)); @@ -113,20 +113,11 @@ calculate_target_mergeinfo(svn_ra_sessio if (! locally_added) { - /* Fetch any existing (explicit) mergeinfo. We'll temporarily - reparent to the target URL here, just to keep the code simple. - We could, as an alternative, first see if the target URL was a - child of the session URL and use the relative "remainder", - falling back to this reparenting as necessary. */ - const char *old_session_url = NULL; - SVN_ERR(svn_client__ensure_ra_session_url(&old_session_url, - ra_session, src_url, pool)); - SVN_ERR(svn_client__get_repos_mergeinfo(ra_session, &src_mergeinfo, - "", src_revnum, - svn_mergeinfo_inherited, TRUE, - FALSE, pool)); - if (old_session_url) - SVN_ERR(svn_ra_reparent(ra_session, old_session_url, pool)); + /* Fetch any existing (explicit) mergeinfo. */ + SVN_ERR(svn_client__get_repos_mergeinfo(&src_mergeinfo, ra_session, + src_url, src_revnum, + svn_mergeinfo_inherited, + TRUE, pool)); } *target_mergeinfo = src_mergeinfo; @@ -150,7 +141,7 @@ extend_wc_mergeinfo(const char *target_a /* Combine the provided mergeinfo with any mergeinfo from the WC. */ if (wc_mergeinfo && mergeinfo) - SVN_ERR(svn_mergeinfo_merge(wc_mergeinfo, mergeinfo, pool)); + SVN_ERR(svn_mergeinfo_merge2(wc_mergeinfo, mergeinfo, pool, pool)); else if (! wc_mergeinfo) wc_mergeinfo = mergeinfo; @@ -240,47 +231,41 @@ get_copy_pair_ancestors(const apr_array_ } -struct do_wc_to_wc_copies_with_write_lock_baton { - const apr_array_header_t *copy_pairs; - svn_client_ctx_t *ctx; - const char *dst_parent; -}; - /* The guts of do_wc_to_wc_copies */ static svn_error_t * -do_wc_to_wc_copies_with_write_lock(void *baton, - apr_pool_t *result_pool, +do_wc_to_wc_copies_with_write_lock(const apr_array_header_t *copy_pairs, + const char *dst_parent, + svn_client_ctx_t *ctx, apr_pool_t *scratch_pool) { - struct do_wc_to_wc_copies_with_write_lock_baton *b = baton; int i; apr_pool_t *iterpool = svn_pool_create(scratch_pool); svn_error_t *err = SVN_NO_ERROR; - for (i = 0; i < b->copy_pairs->nelts; i++) + for (i = 0; i < copy_pairs->nelts; i++) { const char *dst_abspath; - svn_client__copy_pair_t *pair = APR_ARRAY_IDX(b->copy_pairs, i, + svn_client__copy_pair_t *pair = APR_ARRAY_IDX(copy_pairs, i, svn_client__copy_pair_t *); svn_pool_clear(iterpool); /* Check for cancellation */ - if (b->ctx->cancel_func) - SVN_ERR(b->ctx->cancel_func(b->ctx->cancel_baton)); + if (ctx->cancel_func) + SVN_ERR(ctx->cancel_func(ctx->cancel_baton)); /* Perform the copy */ dst_abspath = svn_dirent_join(pair->dst_parent_abspath, pair->base_name, iterpool); - err = svn_wc_copy3(b->ctx->wc_ctx, pair->src_abspath_or_url, dst_abspath, + err = svn_wc_copy3(ctx->wc_ctx, pair->src_abspath_or_url, dst_abspath, FALSE /* metadata_only */, - b->ctx->cancel_func, b->ctx->cancel_baton, - b->ctx->notify_func2, b->ctx->notify_baton2, iterpool); + ctx->cancel_func, ctx->cancel_baton, + ctx->notify_func2, ctx->notify_baton2, iterpool); if (err) break; } svn_pool_destroy(iterpool); - svn_io_sleep_for_timestamps(b->dst_parent, scratch_pool); + svn_io_sleep_for_timestamps(dst_parent, scratch_pool); SVN_ERR(err); return SVN_NO_ERROR; } @@ -293,7 +278,6 @@ do_wc_to_wc_copies(const apr_array_heade apr_pool_t *pool) { const char *dst_parent, *dst_parent_abspath; - struct do_wc_to_wc_copies_with_write_lock_baton baton; SVN_ERR(get_copy_pair_ancestors(copy_pairs, NULL, &dst_parent, NULL, pool)); if (copy_pairs->nelts == 1) @@ -301,40 +285,31 @@ do_wc_to_wc_copies(const apr_array_heade SVN_ERR(svn_dirent_get_absolute(&dst_parent_abspath, dst_parent, pool)); - baton.copy_pairs = copy_pairs; - baton.ctx = ctx; - baton.dst_parent = dst_parent; - SVN_ERR(svn_wc__call_with_write_lock(do_wc_to_wc_copies_with_write_lock, - &baton, ctx->wc_ctx, dst_parent_abspath, - FALSE, pool, pool)); + SVN_WC__CALL_WITH_WRITE_LOCK( + do_wc_to_wc_copies_with_write_lock(copy_pairs, dst_parent, ctx, pool), + ctx->wc_ctx, dst_parent_abspath, FALSE, pool); return SVN_NO_ERROR; } -struct do_wc_to_wc_moves_with_locks_baton { - svn_client_ctx_t *ctx; - svn_client__copy_pair_t *pair; - const char *dst_parent_abspath; - svn_boolean_t lock_src; - svn_boolean_t lock_dst; -}; - /* The locked bit of do_wc_to_wc_moves. */ static svn_error_t * -do_wc_to_wc_moves_with_locks2(void *baton, - apr_pool_t *result_pool, +do_wc_to_wc_moves_with_locks2(svn_client__copy_pair_t *pair, + const char *dst_parent_abspath, + svn_boolean_t lock_src, + svn_boolean_t lock_dst, + svn_client_ctx_t *ctx, apr_pool_t *scratch_pool) { - struct do_wc_to_wc_moves_with_locks_baton *b = baton; const char *dst_abspath; - dst_abspath = svn_dirent_join(b->dst_parent_abspath, b->pair->base_name, + dst_abspath = svn_dirent_join(dst_parent_abspath, pair->base_name, scratch_pool); - SVN_ERR(svn_wc_move(b->ctx->wc_ctx, b->pair->src_abspath_or_url, + SVN_ERR(svn_wc_move(ctx->wc_ctx, pair->src_abspath_or_url, dst_abspath, FALSE /* metadata_only */, - b->ctx->cancel_func, b->ctx->cancel_baton, - b->ctx->notify_func2, b->ctx->notify_baton2, + ctx->cancel_func, ctx->cancel_baton, + ctx->notify_func2, ctx->notify_baton2, scratch_pool)); return SVN_NO_ERROR; @@ -342,18 +317,21 @@ do_wc_to_wc_moves_with_locks2(void *bato /* Wrapper to add an optional second lock */ static svn_error_t * -do_wc_to_wc_moves_with_locks1(void *baton, - apr_pool_t *result_pool, +do_wc_to_wc_moves_with_locks1(svn_client__copy_pair_t *pair, + const char *dst_parent_abspath, + svn_boolean_t lock_src, + svn_boolean_t lock_dst, + svn_client_ctx_t *ctx, apr_pool_t *scratch_pool) { - struct do_wc_to_wc_moves_with_locks_baton *b = baton; - - if (b->lock_dst) - SVN_ERR(svn_wc__call_with_write_lock(do_wc_to_wc_moves_with_locks2, b, - b->ctx->wc_ctx, b->dst_parent_abspath, - FALSE, result_pool, scratch_pool)); + if (lock_dst) + SVN_WC__CALL_WITH_WRITE_LOCK( + do_wc_to_wc_moves_with_locks2(pair, dst_parent_abspath, lock_src, + lock_dst, ctx, scratch_pool), + ctx->wc_ctx, dst_parent_abspath, FALSE, scratch_pool); else - SVN_ERR(do_wc_to_wc_moves_with_locks2(b, result_pool, scratch_pool)); + SVN_ERR(do_wc_to_wc_moves_with_locks2(pair, dst_parent_abspath, lock_src, + lock_dst, ctx, scratch_pool)); return SVN_NO_ERROR; } @@ -373,7 +351,7 @@ do_wc_to_wc_moves(const apr_array_header for (i = 0; i < copy_pairs->nelts; i++) { const char *src_parent_abspath; - struct do_wc_to_wc_moves_with_locks_baton baton; + svn_boolean_t lock_src, lock_dst; svn_client__copy_pair_t *pair = APR_ARRAY_IDX(copy_pairs, i, svn_client__copy_pair_t *); @@ -397,32 +375,31 @@ do_wc_to_wc_moves(const apr_array_header || svn_dirent_is_child(src_parent_abspath, pair->dst_parent_abspath, iterpool)) { - baton.lock_src = TRUE; - baton.lock_dst = FALSE; + lock_src = TRUE; + lock_dst = FALSE; } else if (svn_dirent_is_child(pair->dst_parent_abspath, src_parent_abspath, iterpool)) { - baton.lock_src = FALSE; - baton.lock_dst = TRUE; + lock_src = FALSE; + lock_dst = TRUE; } else { - baton.lock_src = TRUE; - baton.lock_dst = TRUE; + lock_src = TRUE; + lock_dst = TRUE; } /* Perform the copy and then the delete. */ - baton.ctx = ctx; - baton.pair = pair; - baton.dst_parent_abspath = pair->dst_parent_abspath; - if (baton.lock_src) - SVN_ERR(svn_wc__call_with_write_lock(do_wc_to_wc_moves_with_locks1, - &baton, - ctx->wc_ctx, src_parent_abspath, - FALSE, iterpool, iterpool)); + if (lock_src) + SVN_WC__CALL_WITH_WRITE_LOCK( + do_wc_to_wc_moves_with_locks1(pair, pair->dst_parent_abspath, + lock_src, lock_dst, ctx, iterpool), + ctx->wc_ctx, src_parent_abspath, + FALSE, iterpool); else - SVN_ERR(do_wc_to_wc_moves_with_locks1(&baton, iterpool, iterpool)); + SVN_ERR(do_wc_to_wc_moves_with_locks1(pair, pair->dst_parent_abspath, + lock_src, lock_dst, ctx, iterpool)); } svn_pool_destroy(iterpool); @@ -761,7 +738,7 @@ repos_to_repos_copy(const apr_array_head 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, *ignored_url; + const char *message, *repos_root; svn_revnum_t youngest = SVN_INVALID_REVNUM; svn_ra_session_t *ra_session = NULL; const svn_delta_editor_t *editor; @@ -795,8 +772,6 @@ repos_to_repos_copy(const apr_array_head svn_client__copy_pair_t *pair = APR_ARRAY_IDX(copy_pairs, i, svn_client__copy_pair_t *); apr_hash_t *mergeinfo; - svn_opt_revision_t *src_rev, *ignored_rev, dead_end_rev; - dead_end_rev.kind = svn_opt_revision_unspecified; /* Are the source and destination URLs at or under REPOS_ROOT? */ if (! (svn_uri__is_ancestor(repos_root, pair->src_abspath_or_url) @@ -806,31 +781,20 @@ repos_to_repos_copy(const apr_array_head _("Source and destination URLs appear not to point to the " "same repository.")); - /* Resolve revision keywords and such into real revision number, - passing NULL for the path (to ensure error if trying to get a - revision based on the working copy). */ - SVN_ERR(svn_client__get_revision_number(&pair->src_revnum, &youngest, - ctx->wc_ctx, NULL, - ra_session, - &pair->src_op_revision, pool)); - - /* Run the history function to get the source's URL in the + /* Run the history function to get the source's URL and revnum in the operational revision. */ - SVN_ERR(svn_client__ensure_ra_session_url(&ignored_url, ra_session, - pair->src_abspath_or_url, - pool)); - SVN_ERR(svn_client__repos_locations(&pair->src_abspath_or_url, &src_rev, - &ignored_url, &ignored_rev, + 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, + NULL, NULL, ra_session, pair->src_abspath_or_url, &pair->src_peg_revision, - &pair->src_op_revision, - &dead_end_rev, ctx, pool)); + &pair->src_op_revision, NULL, + ctx, pool)); /* Go ahead and grab mergeinfo from the source, too. */ - SVN_ERR(svn_client__ensure_ra_session_url(&ignored_url, ra_session, - pair->src_abspath_or_url, - pool)); + SVN_ERR(svn_ra_reparent(ra_session, pair->src_abspath_or_url, pool)); SVN_ERR(calculate_target_mergeinfo(ra_session, &mergeinfo, NULL, pair->src_abspath_or_url, pair->src_revnum, ctx, pool)); @@ -895,16 +859,13 @@ repos_to_repos_copy(const apr_array_head } /* Point the RA session to our current TOP_URL. */ - SVN_ERR(svn_client__ensure_ra_session_url(&ignored_url, ra_session, - top_url, pool)); + 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) { - const char *dir; - new_dirs = apr_array_make(pool, 0, sizeof(const char *)); /* If this is a move, TOP_URL is at least the common ancestor of @@ -927,17 +888,17 @@ repos_to_repos_copy(const apr_array_head svn copy --parents URL/src URL/dst - where src exists and dst does not. The svn_uri_dirname() - call above will produce a string equivalent to TOP_URL, - which means svn_uri_is_child() will return NULL. In this - case, do not try to add dst to the NEW_DIRS list since it + 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. */ - dir = svn_uri__is_child( - top_url, - svn_uri_dirname(first_pair->dst_abspath_or_url, pool), - pool); - if (dir) + 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 @@ -956,8 +917,9 @@ repos_to_repos_copy(const apr_array_head for (i = 0; i < new_urls->nelts; i++) { const char *new_url = APR_ARRAY_IDX(new_urls, i, const char *); - dir = svn_uri__is_child(top_url, new_url, pool); - APR_ARRAY_PUSH(new_dirs, const char *) = dir ? dir : ""; + const char *dir = svn_uri_skip_ancestor(top_url, new_url, pool); + + APR_ARRAY_PUSH(new_dirs, const char *) = dir; } } } @@ -973,10 +935,12 @@ repos_to_repos_copy(const apr_array_head svn_client__copy_pair_t *); path_driver_info_t *info = APR_ARRAY_IDX(path_infos, i, path_driver_info_t *); + const char *relpath = svn_uri_skip_ancestor(pair->dst_abspath_or_url, + pair->src_abspath_or_url, + pool); if ((strcmp(pair->dst_abspath_or_url, repos_root) != 0) - && (svn_uri__is_child(pair->dst_abspath_or_url, - pair->src_abspath_or_url, pool) != NULL)) + && (relpath != NULL && *relpath != '\0')) { info->resurrection = TRUE; top_url = svn_uri_dirname(top_url, pool); @@ -1000,21 +964,15 @@ repos_to_repos_copy(const apr_array_head svn_node_kind_t dst_kind; const char *src_rel, *dst_rel; - src_rel = svn_uri__is_child(top_url, pair->src_abspath_or_url, pool); + 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 if (strcmp(pair->src_abspath_or_url, top_url) == 0) - { - src_rel = ""; - SVN_ERR(svn_ra_check_path(ra_session, src_rel, pair->src_revnum, - &info->src_kind, pool)); - } else { - const char *old_url = NULL; + const char *old_url; src_rel = NULL; SVN_ERR_ASSERT(! is_move); @@ -1033,9 +991,7 @@ 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__is_child(top_url, pair->dst_abspath_or_url, pool); - if (! dst_rel) - dst_rel = ""; + dst_rel = svn_uri_skip_ancestor(top_url, pair->dst_abspath_or_url, pool); SVN_ERR(svn_ra_check_path(ra_session, dst_rel, youngest, &dst_kind, pool)); if (dst_kind != svn_node_none) @@ -1289,9 +1245,8 @@ wc_to_repos_copy(const apr_array_header_ APR_ARRAY_IDX(copy_pairs, i, svn_client__copy_pair_t *); svn_pool_clear(iterpool); - dst_rel = svn_uri__is_child(top_dst_url, - pair->dst_abspath_or_url, - iterpool); + dst_rel = svn_uri_skip_ancestor(top_dst_url, pair->dst_abspath_or_url, + iterpool); SVN_ERR(svn_ra_check_path(ra_session, dst_rel, SVN_INVALID_REVNUM, &dst_kind, iterpool)); if (dst_kind != svn_node_none) @@ -1412,7 +1367,8 @@ wc_to_repos_copy(const apr_array_header_ pair->src_abspath_or_url, iterpool, iterpool)); if (wc_mergeinfo && mergeinfo) - SVN_ERR(svn_mergeinfo_merge(mergeinfo, wc_mergeinfo, iterpool)); + SVN_ERR(svn_mergeinfo_merge2(mergeinfo, wc_mergeinfo, iterpool, + iterpool)); else if (! mergeinfo) mergeinfo = wc_mergeinfo; if (mergeinfo) @@ -1757,8 +1713,9 @@ repos_to_wc_copy_locked(const apr_array_ parent = top_dst_path; SVN_ERR(svn_dirent_get_absolute(&parent_abspath, parent, scratch_pool)); - dst_err = svn_client_uuid_from_path2(&dst_uuid, parent_abspath, ctx, - scratch_pool, scratch_pool); + dst_err = svn_client_get_repos_root(NULL /* root_url */, &dst_uuid, + parent_abspath, ctx, + scratch_pool, scratch_pool); if (dst_err && dst_err->apr_err != SVN_ERR_RA_NO_REPOS_UUID) return dst_err; @@ -1793,29 +1750,6 @@ repos_to_wc_copy_locked(const apr_array_ return SVN_NO_ERROR; } -struct repos_to_wc_copy_baton { - const apr_array_header_t *copy_pairs; - const char *top_dst_path; - svn_boolean_t ignore_externals; - svn_ra_session_t *ra_session; - svn_client_ctx_t *ctx; -}; - -/* Implements svn_wc__with_write_lock_func_t. */ -static svn_error_t * -repos_to_wc_copy_cb(void *baton, - apr_pool_t *result_pool, - apr_pool_t *scratch_pool) -{ - struct repos_to_wc_copy_baton *b = baton; - - SVN_ERR(repos_to_wc_copy_locked(b->copy_pairs, b->top_dst_path, - b->ignore_externals, b->ra_session, - b->ctx, scratch_pool)); - - return SVN_NO_ERROR; -} - static svn_error_t * repos_to_wc_copy(const apr_array_header_t *copy_pairs, svn_boolean_t make_parents, @@ -1827,7 +1761,6 @@ repos_to_wc_copy(const apr_array_header_ const char *top_src_url, *top_dst_path; apr_pool_t *iterpool = svn_pool_create(pool); const char *lock_abspath; - struct repos_to_wc_copy_baton baton; int i; /* Get the real path for the source, based upon its peg revision. */ @@ -1835,19 +1768,15 @@ repos_to_wc_copy(const apr_array_header_ { svn_client__copy_pair_t *pair = APR_ARRAY_IDX(copy_pairs, i, svn_client__copy_pair_t *); - const char *src, *ignored_url; - svn_opt_revision_t *new_rev, *ignored_rev, dead_end_rev; + const char *src; svn_pool_clear(iterpool); - dead_end_rev.kind = svn_opt_revision_unspecified; - SVN_ERR(svn_client__repos_locations(&src, &new_rev, - &ignored_url, &ignored_rev, + SVN_ERR(svn_client__repos_locations(&src, &pair->src_revnum, NULL, NULL, NULL, pair->src_abspath_or_url, &pair->src_peg_revision, - &pair->src_op_revision, - &dead_end_rev, + &pair->src_op_revision, NULL, ctx, iterpool)); pair->src_original = pair->src_abspath_or_url; @@ -1870,18 +1799,6 @@ repos_to_wc_copy(const apr_array_header_ NULL, NULL, FALSE, TRUE, ctx, pool)); - /* Pass null for the path, to ensure error if trying to get a - revision based on the working copy. */ - for (i = 0; i < copy_pairs->nelts; i++) - { - svn_client__copy_pair_t *pair = APR_ARRAY_IDX(copy_pairs, i, - svn_client__copy_pair_t *); - - SVN_ERR(svn_client__get_revision_number(&pair->src_revnum, NULL, - ctx->wc_ctx, NULL, ra_session, - &pair->src_op_revision, pool)); - } - /* Get the correct src path for the peg revision used, and verify that we aren't overwriting an existing path. */ for (i = 0; i < copy_pairs->nelts; i++) @@ -1943,15 +1860,10 @@ repos_to_wc_copy(const apr_array_header_ } svn_pool_destroy(iterpool); - baton.copy_pairs = copy_pairs; - baton.top_dst_path = top_dst_path; - baton.ignore_externals = ignore_externals; - baton.ra_session = ra_session; - baton.ctx = ctx; - - SVN_ERR(svn_wc__call_with_write_lock(repos_to_wc_copy_cb, &baton, - ctx->wc_ctx, lock_abspath, - FALSE, pool, pool)); + SVN_WC__CALL_WITH_WRITE_LOCK( + repos_to_wc_copy_locked(copy_pairs, top_dst_path, ignore_externals, + ra_session, ctx, pool), + ctx->wc_ctx, lock_abspath, FALSE, pool); return SVN_NO_ERROR; } @@ -2161,9 +2073,9 @@ try_copy(const apr_array_header_t *sourc { if (!srcs_are_urls) { - /* If we are doing a wc->* move, but with an operational revision + /* If we are doing a wc->* copy, but with an operational revision other than the working copy revision, we are really doing a - repo->* move, because we're going to need to get the rev from the + repo->* copy, because we're going to need to get the rev from the repo. */ svn_boolean_t need_repos_op_rev = FALSE; @@ -2206,7 +2118,7 @@ try_copy(const apr_array_header_t *sourc SVN_ERR(svn_wc__node_get_origin(NULL, ©from_rev, ©from_repos_relpath, ©from_repos_root_url, - NULL, + NULL, NULL, ctx->wc_ctx, pair->src_abspath_or_url, TRUE, iterpool, iterpool)); Modified: subversion/branches/revprop-packing/subversion/libsvn_client/delete.c URL: http://svn.apache.org/viewvc/subversion/branches/revprop-packing/subversion/libsvn_client/delete.c?rev=1231318&r1=1231317&r2=1231318&view=diff ============================================================================== --- subversion/branches/revprop-packing/subversion/libsvn_client/delete.c (original) +++ subversion/branches/revprop-packing/subversion/libsvn_client/delete.c Fri Jan 13 21:40:26 2012 @@ -237,7 +237,7 @@ delete_urls_multi_repos(const apr_array_ for (hi = apr_hash_first(pool, sessions); hi; hi = apr_hash_next(hi)) { repos_root = svn__apr_hash_index_key(hi); - repos_relpath = svn_uri__is_child(repos_root, uri, pool); + repos_relpath = svn_uri_skip_ancestor(repos_root, uri, pool); if (repos_relpath) { @@ -264,7 +264,7 @@ delete_urls_multi_repos(const apr_array_ SVN_ERR(svn_ra_reparent(ra_session, repos_root, pool)); apr_hash_set(sessions, repos_root, APR_HASH_KEY_STRING, ra_session); - repos_relpath = svn_uri__is_child(repos_root, uri, pool); + repos_relpath = svn_uri_skip_ancestor(repos_root, uri, pool); relpaths_list = apr_array_make(pool, 1, sizeof(const char *)); apr_hash_set(relpaths, repos_root, APR_HASH_KEY_STRING, @@ -272,6 +272,12 @@ delete_urls_multi_repos(const apr_array_ APR_ARRAY_PUSH(relpaths_list, const char *) = repos_relpath; } + /* Check we identified a non-root relpath. Return an RA error + code for 1.6 compatibility. */ + if (!repos_relpath || !*repos_relpath) + return svn_error_createf(SVN_ERR_RA_ILLEGAL_URL, NULL, + "URL '%s' not within a repository", uri); + /* Now, test to see if the thing actually exists. */ SVN_ERR(svn_ra_check_path(ra_session, repos_relpath, SVN_INVALID_REVNUM, &kind, pool)); @@ -329,29 +335,43 @@ svn_client__wc_delete(const char *path, return SVN_NO_ERROR; } -/* Callback baton for delete_with_write_lock_baton. */ -struct delete_with_write_lock_baton -{ - const char *path; - svn_boolean_t force; - svn_boolean_t keep_local; - svn_client_ctx_t *ctx; -}; - -/* Implements svn_wc__with_write_lock_func_t. */ -static svn_error_t * -delete_with_write_lock_func(void *baton, - apr_pool_t *result_pool, - apr_pool_t *scratch_pool) +svn_error_t * +svn_client__wc_delete_many(const apr_array_header_t *targets, + svn_boolean_t force, + svn_boolean_t dry_run, + svn_boolean_t keep_local, + svn_wc_notify_func2_t notify_func, + void *notify_baton, + svn_client_ctx_t *ctx, + apr_pool_t *pool) { - struct delete_with_write_lock_baton *args = baton; + int i; + apr_array_header_t *abs_targets; + + abs_targets = apr_array_make(pool, targets->nelts, sizeof(const char *)); + for (i = 0; i < targets->nelts; i++) + { + const char *path = APR_ARRAY_IDX(targets, i, const char *); + const char *local_abspath; + + SVN_ERR(svn_dirent_get_absolute(&local_abspath, path, pool)); + APR_ARRAY_PUSH(abs_targets, const char *) = local_abspath; + + if (!force && !keep_local) + /* Verify that there are no "awkward" files */ + SVN_ERR(svn_client__can_delete(local_abspath, ctx, pool)); + } + + if (!dry_run) + /* Mark the entry for commit deletion and perform wc deletion */ + return svn_error_trace(svn_wc__delete_many(ctx->wc_ctx, abs_targets, + keep_local, TRUE, + ctx->cancel_func, + ctx->cancel_baton, + notify_func, notify_baton, + pool)); - /* Let the working copy library handle the PATH. */ - return svn_client__wc_delete(args->path, args->force, - FALSE, args->keep_local, - args->ctx->notify_func2, - args->ctx->notify_baton2, - args->ctx, scratch_pool); + return SVN_NO_ERROR; } svn_error_t * @@ -379,32 +399,75 @@ svn_client_delete4(const apr_array_heade } else { - apr_pool_t *subpool = svn_pool_create(pool); + const char *local_abspath; + apr_hash_t *wcroots; + apr_hash_index_t *hi; int i; - + int j; + apr_pool_t *iterpool; + svn_boolean_t is_new_target; + + /* Build a map of wcroots and targets within them. */ + wcroots = apr_hash_make(pool); + iterpool = svn_pool_create(pool); for (i = 0; i < paths->nelts; i++) { - struct delete_with_write_lock_baton dwwlb; - const char *path = APR_ARRAY_IDX(paths, i, const char *); - const char *local_abspath; + const char *wcroot_abspath; + apr_array_header_t *targets; - svn_pool_clear(subpool); + svn_pool_clear(iterpool); /* See if the user wants us to stop. */ if (ctx->cancel_func) SVN_ERR(ctx->cancel_func(ctx->cancel_baton)); - SVN_ERR(svn_dirent_get_absolute(&local_abspath, path, subpool)); - dwwlb.path = path; - dwwlb.force = force; - dwwlb.keep_local = keep_local; - dwwlb.ctx = ctx; - SVN_ERR(svn_wc__call_with_write_lock(delete_with_write_lock_func, - &dwwlb, ctx->wc_ctx, - local_abspath, TRUE, - pool, subpool)); + SVN_ERR(svn_dirent_get_absolute(&local_abspath, + APR_ARRAY_IDX(paths, i, + const char *), + pool)); + SVN_ERR(svn_wc__get_wc_root(&wcroot_abspath, ctx->wc_ctx, + local_abspath, pool, iterpool)); + targets = apr_hash_get(wcroots, wcroot_abspath, + APR_HASH_KEY_STRING); + if (targets == NULL) + { + targets = apr_array_make(pool, 1, sizeof(const char *)); + apr_hash_set(wcroots, wcroot_abspath, APR_HASH_KEY_STRING, + targets); + } + + /* Make sure targets are unique. */ + is_new_target = TRUE; + for (j = 0; j < targets->nelts; j++) + { + if (strcmp(APR_ARRAY_IDX(targets, j, const char *), + local_abspath) == 0) + { + is_new_target = FALSE; + break; + } + } + + if (is_new_target) + APR_ARRAY_PUSH(targets, const char *) = local_abspath; + } + + /* Delete the targets from each working copy in turn. */ + for (hi = apr_hash_first(pool, wcroots); hi; hi = apr_hash_next(hi)) + { + const char *wcroot_abspath = svn__apr_hash_index_key(hi); + const apr_array_header_t *targets = svn__apr_hash_index_val(hi); + + svn_pool_clear(iterpool); + + SVN_WC__CALL_WITH_WRITE_LOCK( + svn_client__wc_delete_many(targets, force, FALSE, keep_local, + ctx->notify_func2, ctx->notify_baton2, + ctx, iterpool), + ctx->wc_ctx, wcroot_abspath, TRUE /* lock_anchor */, + iterpool); } - svn_pool_destroy(subpool); + svn_pool_destroy(iterpool); } return SVN_NO_ERROR; Modified: subversion/branches/revprop-packing/subversion/libsvn_client/deprecated.c URL: http://svn.apache.org/viewvc/subversion/branches/revprop-packing/subversion/libsvn_client/deprecated.c?rev=1231318&r1=1231317&r2=1231318&view=diff ============================================================================== --- subversion/branches/revprop-packing/subversion/libsvn_client/deprecated.c (original) +++ subversion/branches/revprop-packing/subversion/libsvn_client/deprecated.c Fri Jan 13 21:40:26 2012 @@ -39,10 +39,12 @@ #include "svn_props.h" #include "svn_utf.h" #include "svn_string.h" +#include "svn_pools.h" #include "client.h" #include "mergeinfo.h" +#include "private/svn_opt_private.h" #include "private/svn_wc_private.h" #include "svn_private_config.h" @@ -837,6 +839,37 @@ svn_client_delete(svn_client_commit_info /*** From diff.c ***/ svn_error_t * +svn_client_diff5(const apr_array_header_t *diff_options, + const char *path1, + const svn_opt_revision_t *revision1, + const char *path2, + const svn_opt_revision_t *revision2, + const char *relative_to_dir, + svn_depth_t depth, + svn_boolean_t ignore_ancestry, + svn_boolean_t no_diff_deleted, + svn_boolean_t show_copies_as_adds, + svn_boolean_t ignore_content_type, + svn_boolean_t use_git_diff_format, + const char *header_encoding, + apr_file_t *outfile, + apr_file_t *errfile, + const apr_array_header_t *changelists, + svn_client_ctx_t *ctx, + apr_pool_t *pool) +{ + svn_stream_t *outstream = svn_stream_from_aprfile2(outfile, TRUE, pool); + svn_stream_t *errstream = svn_stream_from_aprfile2(errfile, TRUE, pool); + + return svn_client_diff6(diff_options, path1, revision1, path2, + revision2, relative_to_dir, depth, + ignore_ancestry, no_diff_deleted, + show_copies_as_adds, ignore_content_type, + use_git_diff_format, header_encoding, + outstream, errstream, changelists, ctx, pool); +} + +svn_error_t * svn_client_diff4(const apr_array_header_t *options, const char *path1, const svn_opt_revision_t *revision1, @@ -926,6 +959,49 @@ svn_client_diff(const apr_array_header_t } svn_error_t * +svn_client_diff_peg5(const apr_array_header_t *diff_options, + const char *path, + const svn_opt_revision_t *peg_revision, + const svn_opt_revision_t *start_revision, + const svn_opt_revision_t *end_revision, + const char *relative_to_dir, + svn_depth_t depth, + svn_boolean_t ignore_ancestry, + svn_boolean_t no_diff_deleted, + svn_boolean_t show_copies_as_adds, + svn_boolean_t ignore_content_type, + svn_boolean_t use_git_diff_format, + const char *header_encoding, + apr_file_t *outfile, + apr_file_t *errfile, + const apr_array_header_t *changelists, + svn_client_ctx_t *ctx, + apr_pool_t *pool) +{ + svn_stream_t *outstream = svn_stream_from_aprfile2(outfile, TRUE, pool); + svn_stream_t *errstream = svn_stream_from_aprfile2(errfile, TRUE, pool); + + return svn_client_diff_peg6(diff_options, + path, + peg_revision, + start_revision, + end_revision, + relative_to_dir, + depth, + ignore_ancestry, + no_diff_deleted, + show_copies_as_adds, + ignore_content_type, + use_git_diff_format, + header_encoding, + outstream, + errstream, + changelists, + ctx, + pool); +} + +svn_error_t * svn_client_diff_peg4(const apr_array_header_t *options, const char *path, const svn_opt_revision_t *peg_revision, @@ -1287,16 +1363,11 @@ svn_client_log4(const apr_array_header_t apr_pool_t *pool) { apr_array_header_t *revision_ranges; - svn_opt_revision_range_t *range; - - range = apr_palloc(pool, sizeof(svn_opt_revision_range_t)); - range->start = *start; - range->end = *end; revision_ranges = apr_array_make(pool, 1, sizeof(svn_opt_revision_range_t *)); - - APR_ARRAY_PUSH(revision_ranges, svn_opt_revision_range_t *) = range; + APR_ARRAY_PUSH(revision_ranges, svn_opt_revision_range_t *) + = svn_opt__revision_range_create(start, end, pool); return svn_client_log5(targets, peg_revision, revision_ranges, limit, discover_changed_paths, strict_node_history, @@ -1502,13 +1573,11 @@ svn_client_merge_peg2(const char *source svn_client_ctx_t *ctx, apr_pool_t *pool) { - svn_opt_revision_range_t range; apr_array_header_t *ranges_to_merge = apr_array_make(pool, 1, sizeof(svn_opt_revision_range_t *)); - range.start = *revision1; - range.end = *revision2; - APR_ARRAY_PUSH(ranges_to_merge, svn_opt_revision_range_t *) = ⦥ + APR_ARRAY_PUSH(ranges_to_merge, svn_opt_revision_range_t *) + = svn_opt__revision_range_create(revision1, revision2, pool); return svn_client_merge_peg3(source, ranges_to_merge, peg_revision, target_wcpath, @@ -2390,6 +2459,41 @@ svn_client_revert(const apr_array_header /*** From ra.c ***/ svn_error_t * +svn_client_uuid_from_url(const char **uuid, + const char *url, + svn_client_ctx_t *ctx, + apr_pool_t *pool) +{ + svn_ra_session_t *ra_session; + apr_pool_t *subpool = svn_pool_create(pool); + + /* use subpool to create a temporary RA session */ + SVN_ERR(svn_client__open_ra_session_internal(&ra_session, NULL, url, + NULL, /* no base dir */ + NULL, FALSE, TRUE, + ctx, subpool)); + + SVN_ERR(svn_ra_get_uuid2(ra_session, uuid, pool)); + + /* destroy the RA session */ + svn_pool_destroy(subpool); + + return SVN_NO_ERROR; +} + +svn_error_t * +svn_client_uuid_from_path2(const char **uuid, + const char *local_abspath, + svn_client_ctx_t *ctx, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool) +{ + return svn_error_trace( + svn_wc__node_get_repos_info(NULL, uuid, ctx->wc_ctx, local_abspath, + result_pool, scratch_pool)); +} + +svn_error_t * svn_client_uuid_from_path(const char **uuid, const char *path, svn_wc_adm_access_t *adm_access, @@ -2405,6 +2509,20 @@ svn_client_uuid_from_path(const char **u /*** From url.c ***/ svn_error_t * +svn_client_root_url_from_path(const char **url, + const char *path_or_url, + svn_client_ctx_t *ctx, + apr_pool_t *pool) +{ + if (!svn_path_is_url(path_or_url)) + SVN_ERR(svn_dirent_get_absolute(&path_or_url, path_or_url, pool)); + + return svn_error_trace( + svn_client_get_repos_root(url, NULL, path_or_url, + ctx, pool, pool)); +} + +svn_error_t * svn_client_url_from_path(const char **url, const char *path_or_url, apr_pool_t *pool)
