Modified: subversion/branches/multi-wc-format/subversion/libsvn_client/merge.c URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/subversion/libsvn_client/merge.c?rev=1897034&r1=1897033&r2=1897034&view=diff ============================================================================== --- subversion/branches/multi-wc-format/subversion/libsvn_client/merge.c (original) +++ subversion/branches/multi-wc-format/subversion/libsvn_client/merge.c Fri Jan 14 14:01:45 2022 @@ -51,6 +51,7 @@ #include "svn_sorts.h" #include "svn_subst.h" #include "svn_ra.h" +#include "svn_version.h" #include "client.h" #include "mergeinfo.h" @@ -264,7 +265,7 @@ typedef struct merge_cmd_baton_t { /* Reference to the one-and-only CHILDREN_WITH_MERGEINFO (see global comment) or a similar list for single-file-merges */ - const apr_array_header_t *children_with_mergeinfo; + apr_array_header_t *children_with_mergeinfo; svn_client_ctx_t *ctx; /* Client context for callbacks, etc. */ @@ -422,6 +423,37 @@ merge_source_dup(const merge_source_t *s return s; } +/* Decide whether ambiguous foreign merge should be a warning or an error */ +#define WITH_AMBIGUOUS_FOREIGN_MERGE_WARNING \ + (SVN_VER_MAJOR == 1 && SVN_VER_MINOR < 16) + +#if WITH_AMBIGUOUS_FOREIGN_MERGE_WARNING +/* Notify a warning, given in WARNING, if WARNING is non-null. + * + * We plan to replace this with a hard error in Subversion 1.16. + * This clears the error object WARNING before returning. + */ +static void +notify_pre_1_16_warning(svn_error_t *warning, + svn_client_ctx_t *ctx, + apr_pool_t *pool) +{ + if (!warning) + return; + + if (ctx->notify_func2) + { + svn_wc_notify_t *n + = svn_wc_create_notify("" /*path*/, svn_wc_notify_warning, pool); + + n->err = svn_error_quick_wrap(warning, + _("In Subversion 1.16 this warning will become a fatal error")); + ctx->notify_func2(ctx->notify_baton2, n, pool); + } + svn_error_clear(warning); +} +#endif + /* Return SVN_ERR_UNSUPPORTED_FEATURE if URL is not inside the repository of LOCAL_ABSPATH. Use SCRATCH_POOL for temporary allocations. */ static svn_error_t * @@ -440,38 +472,70 @@ check_repos_match(const merge_target_t * return SVN_NO_ERROR; } -/* Return TRUE iff the repository of LOCATION1 is the same as - * that of LOCATION2. If STRICT_URLS is true, the URLs must - * match (and the UUIDs, just to be sure), otherwise just the UUIDs must - * match and the URLs can differ (a common case is http versus https). */ -static svn_boolean_t -is_same_repos(const svn_client__pathrev_t *location1, +/* Decide whether LOCATION1 and LOCATION2 point to the same repository + * (with the same root URL) or to two different repositories. + * - same repository root URL -> set *SAME_REPOS true + * - different repositories -> set *SAME_REPOS false + * - different URLs but same UUID -> return an error + * + * The last case is unsupported for practical and historical reasons + * (see issue #4874) even though different URLs pointing to the same or + * equivalent repositories could be supported in principle. + */ +static svn_error_t * +is_same_repos(svn_boolean_t *same_repos, + const svn_client__pathrev_t *location1, + const char *path1, const svn_client__pathrev_t *location2, - svn_boolean_t strict_urls) + const char *path2, + const char *message) { - if (strict_urls) - return (strcmp(location1->repos_root_url, location2->repos_root_url) == 0 - && strcmp(location1->repos_uuid, location2->repos_uuid) == 0); + if (strcmp(location1->repos_root_url, location2->repos_root_url) == 0) + *same_repos = TRUE; + else if (strcmp(location1->repos_uuid, location2->repos_uuid) != 0) + *same_repos = FALSE; else - return (strcmp(location1->repos_uuid, location2->repos_uuid) == 0); + { + svn_error_t *err + = svn_error_create(SVN_ERR_CLIENT_UNRELATED_RESOURCES, NULL, message); + + return svn_error_quick_wrapf(err, + _("The locations '%s' and '%s' point to repositories with the " + "same repository UUID using different repository root URLs " + "('%s' and '%s')"), + path1, path2, + location1->repos_root_url, location2->repos_root_url); + } + return SVN_NO_ERROR; } -/* If the repository identified of LOCATION1 is not the same as that - * of LOCATION2, throw a SVN_ERR_CLIENT_UNRELATED_RESOURCES - * error mentioning PATH1 and PATH2. For STRICT_URLS, see is_same_repos(). +/* Check that LOCATION1 and LOCATION2 point to the same repository, with + * the same root URL. If not, throw a SVN_ERR_CLIENT_UNRELATED_RESOURCES + * error mentioning PATH_OR_URL1 and PATH_OR_URL2. */ static svn_error_t * check_same_repos(const svn_client__pathrev_t *location1, - const char *path1, + const char *path_or_url1, const svn_client__pathrev_t *location2, - const char *path2, - svn_boolean_t strict_urls, - apr_pool_t *scratch_pool) + const char *path_or_url2, + const char *message) { - if (! is_same_repos(location1, location2, strict_urls)) - return svn_error_createf(SVN_ERR_CLIENT_UNRELATED_RESOURCES, NULL, - _("'%s' must be from the same repository as " - "'%s'"), path1, path2); + svn_boolean_t same_repos; + + SVN_ERR(is_same_repos(&same_repos, + location1, path_or_url1, location2, path_or_url2, + message)); + if (! same_repos) + { + svn_error_t *err + = svn_error_create(SVN_ERR_CLIENT_UNRELATED_RESOURCES, NULL, message); + + return svn_error_quick_wrapf(err, + _("The locations '%s' and '%s' point to different repositories " + "(root URLs '%s' and '%s', and differing UUIDs)"), + path_or_url1, path_or_url2, + location1->repos_root_url, location2->repos_root_url); + } return SVN_NO_ERROR; } @@ -1545,6 +1609,25 @@ record_update_delete(merge_cmd_baton_t * svn_node_kind_to_word(kind)); } + /* Note in children_with_mergeinfo that all paths in this subtree are + * being deleted, to avoid trying to set mergeinfo on them later. */ + if (merge_b->children_with_mergeinfo) + { + int i; + + for (i = 0; i < merge_b->children_with_mergeinfo->nelts; i++) + { + svn_client__merge_path_t *child + = APR_ARRAY_IDX(merge_b->children_with_mergeinfo, i, + svn_client__merge_path_t *); + + if (svn_dirent_is_ancestor(local_abspath, child->abspath)) + { + SVN_ERR(svn_sort__array_delete2(merge_b->children_with_mergeinfo, i--, 1)); + } + } + } + return SVN_NO_ERROR; } @@ -3387,7 +3470,7 @@ merge_dir_closed(const char *relpath, We register a skipped path, which will make parent mergeinfo non- inheritable. This ensures that a future merge might see these skipped - changes as eligable for merging. + changes as eligible for merging. For legacy reasons we also notify the path as skipped. */ @@ -5595,9 +5678,9 @@ svn_client__make_merge_conflict_error(sv with paths (svn_client__merge_path_t *) arranged in depth first order, which have mergeinfo set on them or meet one of the other criteria defined in get_mergeinfo_paths(). Remove any paths absent from disk - or scheduled for deletion from CHILDREN_WITH_MERGEINFO which are equal to + from CHILDREN_WITH_MERGEINFO which are equal to or are descendants of TARGET_WCPATH by setting those children to NULL. */ -static void +static svn_error_t * remove_absent_children(const char *target_wcpath, apr_array_header_t *children_with_mergeinfo) { @@ -5609,12 +5692,13 @@ remove_absent_children(const char *targe { svn_client__merge_path_t *child = APR_ARRAY_IDX(children_with_mergeinfo, i, svn_client__merge_path_t *); - if ((child->absent || child->scheduled_for_deletion) + if (child->absent && svn_dirent_is_ancestor(target_wcpath, child->abspath)) { - svn_sort__array_delete(children_with_mergeinfo, i--, 1); + SVN_ERR(svn_sort__array_delete2(children_with_mergeinfo, i--, 1)); } } + return SVN_NO_ERROR; } /* Helper for do_directory_merge() to handle the case where a merge editor @@ -5629,14 +5713,14 @@ remove_absent_children(const char *targe MERGE_B->target->abspath, this must always be present in CHILDREN_WITH_MERGEINFO so this is never removed by this function. */ -static void +static svn_error_t * remove_children_with_deleted_mergeinfo(merge_cmd_baton_t *merge_b, apr_array_header_t *children_with_mergeinfo) { int i; if (!merge_b->paths_with_deleted_mergeinfo) - return; + return SVN_NO_ERROR; /* CHILDREN_WITH_MERGEINFO[0] is the always the merge target so start at the first child. */ @@ -5647,9 +5731,10 @@ remove_children_with_deleted_mergeinfo(m if (svn_hash_gets(merge_b->paths_with_deleted_mergeinfo, child->abspath)) { - svn_sort__array_delete(children_with_mergeinfo, i--, 1); + SVN_ERR(svn_sort__array_delete2(children_with_mergeinfo, i--, 1)); } } + return SVN_NO_ERROR; } /* Helper for do_directory_merge(). @@ -5975,7 +6060,7 @@ get_most_inclusive_rev(const apr_array_h remaining_ranges is inclusive of END_REV, Slice the first range in to two at END_REV. All the allocations are persistent and allocated from POOL. */ -static void +static svn_error_t * slice_remaining_ranges(apr_array_header_t *children_with_mergeinfo, svn_boolean_t is_rollback, svn_revnum_t end_rev, apr_pool_t *pool) @@ -6005,10 +6090,12 @@ slice_remaining_ranges(apr_array_header_ split_range2->start = end_rev; APR_ARRAY_IDX(child->remaining_ranges, 0, svn_merge_range_t *) = split_range1; - svn_sort__array_insert(child->remaining_ranges, &split_range2, 1); + SVN_ERR(svn_sort__array_insert2(child->remaining_ranges, + &split_range2, 1)); } } } + return SVN_NO_ERROR; } /* Helper for do_directory_merge(). @@ -6020,7 +6107,7 @@ slice_remaining_ranges(apr_array_header_ If a range is removed from a child's remaining_ranges array, allocate the new remaining_ranges array in POOL. */ -static void +static svn_error_t * remove_first_range_from_remaining_ranges(svn_revnum_t revision, apr_array_header_t *children_with_mergeinfo, @@ -6041,10 +6128,11 @@ remove_first_range_from_remaining_ranges APR_ARRAY_IDX(child->remaining_ranges, 0, svn_merge_range_t *); if (first_range->end == revision) { - svn_sort__array_delete(child->remaining_ranges, 0, 1); + SVN_ERR(svn_sort__array_delete2(child->remaining_ranges, 0, 1)); } } } + return SVN_NO_ERROR; } /* Get a file's content and properties from the repository. @@ -6130,7 +6218,7 @@ get_child_with_mergeinfo(const apr_array out of order and then sort afterwards. (One caller is doing a qsort after calling this anyway.) */ -static void +static svn_error_t * insert_child_to_merge(apr_array_header_t *children_with_mergeinfo, const svn_client__merge_path_t *insert_element, apr_pool_t *pool) @@ -6144,7 +6232,9 @@ insert_child_to_merge(apr_array_header_t compare_merge_path_t_as_paths); new_element = svn_client__merge_path_dup(insert_element, pool); - svn_sort__array_insert(children_with_mergeinfo, &new_element, insert_index); + SVN_ERR(svn_sort__array_insert2(children_with_mergeinfo, + &new_element, insert_index)); + return SVN_NO_ERROR; } /* Helper for get_mergeinfo_paths(). @@ -6205,7 +6295,7 @@ insert_parent_and_sibs_of_sw_absent_del_ parent->missing_child = child->absent; parent->switched_child = child->switched; /* Insert PARENT into CHILDREN_WITH_MERGEINFO. */ - insert_child_to_merge(children_with_mergeinfo, parent, pool); + SVN_ERR(insert_child_to_merge(children_with_mergeinfo, parent, pool)); /* Increment for loop index so we don't process the inserted element. */ (*curr_index)++; } /*(parent == NULL) */ @@ -6242,8 +6332,8 @@ insert_parent_and_sibs_of_sw_absent_del_ sibling_of_missing = svn_client__merge_path_create(child_abspath, pool); - insert_child_to_merge(children_with_mergeinfo, sibling_of_missing, - pool); + SVN_ERR(insert_child_to_merge(children_with_mergeinfo, + sibling_of_missing, pool)); } } @@ -6584,8 +6674,8 @@ get_mergeinfo_paths(apr_array_header_t * svn_client__merge_path_t *switched_child = svn_client__merge_path_create(wc_path, result_pool); switched_child->switched = TRUE; - insert_child_to_merge(children_with_mergeinfo, switched_child, - result_pool); + SVN_ERR(insert_child_to_merge(children_with_mergeinfo, + switched_child, result_pool)); } } } @@ -6637,8 +6727,8 @@ get_mergeinfo_paths(apr_array_header_t * } if (new_shallow_child) - insert_child_to_merge(children_with_mergeinfo, shallow_child, - result_pool); + SVN_ERR(insert_child_to_merge(children_with_mergeinfo, + shallow_child, result_pool)); } } @@ -6667,8 +6757,8 @@ get_mergeinfo_paths(apr_array_header_t * svn_client__merge_path_t *absent_child = svn_client__merge_path_create(wc_path, result_pool); absent_child->absent = TRUE; - insert_child_to_merge(children_with_mergeinfo, absent_child, - result_pool); + SVN_ERR(insert_child_to_merge(children_with_mergeinfo, + absent_child, result_pool)); } } } @@ -6681,8 +6771,8 @@ get_mergeinfo_paths(apr_array_header_t * svn_client__merge_path_t *target_child = svn_client__merge_path_create(target->abspath, result_pool); - insert_child_to_merge(children_with_mergeinfo, target_child, - result_pool); + SVN_ERR(insert_child_to_merge(children_with_mergeinfo, target_child, + result_pool)); } /* Case 8: Path is an immediate *directory* child of @@ -6725,8 +6815,8 @@ get_mergeinfo_paths(apr_array_header_t * && depth == svn_depth_immediates) immediate_child->immediate_child_dir = TRUE; - insert_child_to_merge(children_with_mergeinfo, - immediate_child, result_pool); + SVN_ERR(insert_child_to_merge(children_with_mergeinfo, + immediate_child, result_pool)); } } } @@ -6818,9 +6908,9 @@ get_mergeinfo_paths(apr_array_header_t * child_of_noninheritable = svn_client__merge_path_create(child_abspath, result_pool); child_of_noninheritable->child_of_noninheritable = TRUE; - insert_child_to_merge(children_with_mergeinfo, - child_of_noninheritable, - result_pool); + SVN_ERR(insert_child_to_merge(children_with_mergeinfo, + child_of_noninheritable, + result_pool)); if (!dry_run && same_repos) { svn_mergeinfo_t mergeinfo; @@ -7244,7 +7334,7 @@ normalize_merge_sources_internal(apr_arr new_segment->path = original_repos_relpath; new_segment->range_start = original_revision; new_segment->range_end = original_revision; - svn_sort__array_insert(segments, &new_segment, 0); + SVN_ERR(svn_sort__array_insert2(segments, &new_segment, 0)); } } } @@ -7791,7 +7881,7 @@ do_file_merge(svn_mergeinfo_catalog_t re (This list is used from notify_merge_begin) Directory merges use remove_first_range_from_remaining_ranges() */ - svn_sort__array_delete(ranges_to_merge, 0, 1); + SVN_ERR(svn_sort__array_delete2(ranges_to_merge, 0, 1)); } merge_b->notify_begin.last_abspath = NULL; } /* !merge_b->record_only */ @@ -7889,18 +7979,23 @@ process_children_with_new_mergeinfo(merg apr_pool_t *pool) { apr_pool_t *iterpool; - apr_hash_index_t *hi; + apr_array_header_t *a; + int i; if (!merge_b->paths_with_new_mergeinfo || merge_b->dry_run) return SVN_NO_ERROR; - /* Iterate over each path with explicit mergeinfo added by the merge. */ + /* Iterate over each path with explicit mergeinfo added by the merge. + * Iterate in a parent-to-child order so that inherited + * mergeinfo is propagated consistently from each parent path to its + * children. (Issue #4862) */ + a = svn_sort__hash(merge_b->paths_with_new_mergeinfo, + svn_sort_compare_items_as_paths, pool); iterpool = svn_pool_create(pool); - for (hi = apr_hash_first(pool, merge_b->paths_with_new_mergeinfo); - hi; - hi = apr_hash_next(hi)) + for (i = 0; i < a->nelts; i++) { - const char *abspath_with_new_mergeinfo = apr_hash_this_key(hi); + svn_sort__item_t *item = &APR_ARRAY_IDX(a, i, svn_sort__item_t); + const char *abspath_with_new_mergeinfo = item->key; svn_mergeinfo_t path_inherited_mergeinfo; svn_mergeinfo_t path_explicit_mergeinfo; svn_client__merge_path_t *new_child; @@ -7978,7 +8073,8 @@ process_children_with_new_mergeinfo(merg /* Set the path's remaining_ranges equal to its parent's. */ new_child->remaining_ranges = svn_rangelist_dup( parent->remaining_ranges, pool); - insert_child_to_merge(children_with_mergeinfo, new_child, pool); + SVN_ERR(insert_child_to_merge(children_with_mergeinfo, + new_child, pool)); } } } @@ -8543,8 +8639,8 @@ record_mergeinfo_for_dir_merge(svn_merge /* Remove absent children at or under MERGE_B->target->abspath from CHILDREN_WITH_MERGEINFO before we calculate the merges performed. */ - remove_absent_children(merge_b->target->abspath, - children_with_mergeinfo); + SVN_ERR(remove_absent_children(merge_b->target->abspath, + children_with_mergeinfo)); /* Determine which subtrees of interest need mergeinfo recorded... */ SVN_ERR(flag_subtrees_needing_mergeinfo(operative_merge, &range, @@ -9510,8 +9606,9 @@ do_mergeinfo_aware_dir_merge(svn_mergein svn_pool_clear(iterpool); - slice_remaining_ranges(children_with_mergeinfo, - is_rollback, end_rev, scratch_pool); + SVN_ERR(slice_remaining_ranges(children_with_mergeinfo, + is_rollback, end_rev, + scratch_pool)); /* Reset variables that must be reset for every drive */ merge_b->notify_begin.last_abspath = NULL; @@ -9540,12 +9637,12 @@ do_mergeinfo_aware_dir_merge(svn_mergein to consider these subtrees for subsequent editor drives nor do we want to record mergeinfo on them describing the merge itself. */ - remove_children_with_deleted_mergeinfo( - merge_b, children_with_mergeinfo); + SVN_ERR(remove_children_with_deleted_mergeinfo( + merge_b, children_with_mergeinfo)); /* Prepare for the next iteration (if any). */ - remove_first_range_from_remaining_ranges( - end_rev, children_with_mergeinfo, scratch_pool); + SVN_ERR(remove_first_range_from_remaining_ranges( + end_rev, children_with_mergeinfo, scratch_pool)); /* If we raised any conflicts, break out and report how much we have merged. */ @@ -10498,16 +10595,34 @@ svn_client__merge_locked(svn_client__con source2, NULL, revision2, revision2, ctx, sesspool)); /* We can't do a diff between different repositories. */ - /* ### We should also insist that the root URLs of the two sources match, - * as we are only carrying around a single source-repos-root from now - * on, and URL calculations will go wrong if they differ. - * Alternatively, teach the code to cope with differing root URLs. */ - SVN_ERR(check_same_repos(source1_loc, source1_loc->url, - source2_loc, source2_loc->url, - FALSE /* strict_urls */, scratch_pool)); + err = check_same_repos( + source1_loc, source1, source2_loc, source2, + _("The repository root URLs of the two sources must be identical " + "in a two-URL merge")); + if (err) + /* Add an error code and message compatible with Subversion <= 1.14 */ + return svn_error_createf(SVN_ERR_RA_ILLEGAL_URL, err, + _("'%s' isn't in the same repository as '%s'"), + source1, source2_loc->repos_root_url); /* Do our working copy and sources come from the same repository? */ - same_repos = is_same_repos(&target->loc, source1_loc, TRUE /* strict_urls */); + err = is_same_repos(&same_repos, + source1_loc, source1, &target->loc, target_abspath, + _("The given merge source must have the same repository " + "root URL as the target WC, in the usual case; " + "or, if a foreign repository merge is intended, the repositories " + "must have different root URLs and different UUIDs")); +#if WITH_AMBIGUOUS_FOREIGN_MERGE_WARNING + if (err) + { + /* Subversion 1.14 compatibility: do a foreign-repository merge, + * even though the repository UUIDs are identical. Issue a warning. */ + notify_pre_1_16_warning(err, ctx, scratch_pool); + same_repos = FALSE; + } +#else + SVN_ERR(err); +#endif /* Unless we're ignoring ancestry, see if the two sources are related. */ if (! ignore_mergeinfo) @@ -11713,13 +11828,12 @@ open_reintegrate_source_and_target(svn_r /* source_loc and target->loc are required to be in the same repository, as mergeinfo doesn't come into play for cross-repository merging. */ - SVN_ERR(check_same_repos(source_loc, - svn_dirent_local_style(source_path_or_url, - scratch_pool), - &target->loc, - svn_dirent_local_style(target->abspath, - scratch_pool), - TRUE /* strict_urls */, scratch_pool)); + SVN_ERR(check_same_repos( + source_loc, source_path_or_url, + &target->loc, svn_dirent_local_style(target->abspath, + scratch_pool), + _("The repository root URLs of the source and the target WC " + "must be identical in a reintegrate merge"))); *source_loc_p = source_loc; *target_p = target; @@ -11881,7 +11995,24 @@ merge_peg_locked(svn_client__conflict_re scratch_pool, scratch_pool)); /* Check for same_repos. */ - same_repos = is_same_repos(&target->loc, source_loc, TRUE /* strict_urls */); + err = is_same_repos(&same_repos, + source_loc, source_path_or_url, + &target->loc, target_abspath, + _("The given merge source must have the same repository " + "root URL as the target WC, in the usual case; " + "or, if a foreign repository merge is intended, the repositories " + "must have different root URLs and different UUIDs")); +#if WITH_AMBIGUOUS_FOREIGN_MERGE_WARNING + if (err) + { + /* Subversion 1.14 compatibility: do a foreign-repository merge, + * even though the repository UUIDs are identical. Issue a warning. */ + notify_pre_1_16_warning(err, ctx, scratch_pool); + same_repos = FALSE; + } +#else + SVN_ERR(err); +#endif /* Do the real merge! (We say with confidence that our merge sources are both ancestral and related.) */ @@ -12669,9 +12800,12 @@ client_find_automatic_merge(automatic_me ctx, result_pool)); /* Check source is in same repos as target. */ - SVN_ERR(check_same_repos(s_t->source, source_path_or_url, - &s_t->target->loc, target_abspath, - TRUE /* strict_urls */, scratch_pool)); + SVN_ERR(check_same_repos( + s_t->source, source_path_or_url, + &s_t->target->loc, svn_dirent_local_style(target_abspath, + scratch_pool), + _("The repository root URLs of the source and the target WC " + "must be identical in an automatic merge"))); SVN_ERR(find_automatic_merge(&merge->base, &merge->is_reintegrate_like, s_t, ctx, result_pool, scratch_pool)); @@ -12814,7 +12948,7 @@ do_automatic_merge_locked(svn_client__co for the root path of the merge). An improvement would be to change find_automatic_merge() to - find the base for each sutree, and then here use the oldest base + find the base for each subtree, and then here use the oldest base among all subtrees. */ apr_array_header_t *merge_sources; svn_ra_session_t *ra_session = NULL;
Modified: subversion/branches/multi-wc-format/subversion/libsvn_client/mergeinfo.c URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/subversion/libsvn_client/mergeinfo.c?rev=1897034&r1=1897033&r2=1897034&view=diff ============================================================================== --- subversion/branches/multi-wc-format/subversion/libsvn_client/mergeinfo.c (original) +++ subversion/branches/multi-wc-format/subversion/libsvn_client/mergeinfo.c Fri Jan 14 14:01:45 2022 @@ -1749,7 +1749,7 @@ svn_client__mergeinfo_log(svn_boolean_t if (*target_mergeinfo_catalog) { /* The caller provided the mergeinfo catalog for - TARGET_PATH_OR_URL, so we don't need to accquire + TARGET_PATH_OR_URL, so we don't need to acquire it ourselves. We do need to get the repos_root though, because get_mergeinfo() won't do it for us. */ target_mergeinfo_cat = *target_mergeinfo_catalog; Modified: subversion/branches/multi-wc-format/subversion/libsvn_client/mergeinfo.h URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/subversion/libsvn_client/mergeinfo.h?rev=1897034&r1=1897033&r2=1897034&view=diff ============================================================================== --- subversion/branches/multi-wc-format/subversion/libsvn_client/mergeinfo.h (original) +++ subversion/branches/multi-wc-format/subversion/libsvn_client/mergeinfo.h Fri Jan 14 14:01:45 2022 @@ -74,8 +74,6 @@ typedef struct svn_client__merge_path_t prior to a merge. May be NULL. */ svn_boolean_t inherited_mergeinfo; /* Whether PRE_MERGE_MERGEINFO was explicit or inherited. */ - svn_boolean_t scheduled_for_deletion; /* ABSPATH is scheduled for - deletion. */ svn_boolean_t immediate_child_dir; /* ABSPATH is an immediate child directory of the merge target, has no explicit mergeinfo prior @@ -316,7 +314,7 @@ svn_client__get_history_as_mergeinfo(svn /* Parse any explicit mergeinfo on LOCAL_ABSPATH and store it in *MERGEINFO. If no record of any mergeinfo exists, set *MERGEINFO to NULL. - Does not acount for inherited mergeinfo. + Does not account for inherited mergeinfo. Allocate the result deeply in @a result_pool. */ svn_error_t * Modified: subversion/branches/multi-wc-format/subversion/libsvn_client/mtcc.c URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/subversion/libsvn_client/mtcc.c?rev=1897034&r1=1897033&r2=1897034&view=diff ============================================================================== --- subversion/branches/multi-wc-format/subversion/libsvn_client/mtcc.c (original) +++ subversion/branches/multi-wc-format/subversion/libsvn_client/mtcc.c Fri Jan 14 14:01:45 2022 @@ -453,7 +453,8 @@ mtcc_verify_create(svn_client__mtcc_t *m if (op) return svn_error_createf(SVN_ERR_FS_ALREADY_EXISTS, NULL, - _("Path '%s' already exists"), + _("Path '%s' already exists, or was created " + "by an earlier operation"), new_relpath); SVN_ERR(mtcc_op_find(&op, NULL, new_relpath, mtcc->root_op, TRUE, TRUE, @@ -604,7 +605,7 @@ mtcc_op_contains_non_delete(const mtcc_o static svn_error_t * mtcc_add_delete(const char *relpath, svn_boolean_t for_move, - svn_client__mtcc_t *mtcc, + svn_client__mtcc_t *mtcc, apr_pool_t *scratch_pool) { mtcc_op_t *op; @@ -636,7 +637,7 @@ mtcc_add_delete(const char *relpath, { /* Allow deleting directories, that are unmodified except for one or more deleted descendants */ - + SVN_ERR(mtcc_op_find(&op, &created, relpath, mtcc->root_op, TRUE, FALSE, FALSE, mtcc->pool, scratch_pool)); Modified: subversion/branches/multi-wc-format/subversion/libsvn_client/patch.c URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/subversion/libsvn_client/patch.c?rev=1897034&r1=1897033&r2=1897034&view=diff ============================================================================== --- subversion/branches/multi-wc-format/subversion/libsvn_client/patch.c (original) +++ subversion/branches/multi-wc-format/subversion/libsvn_client/patch.c Fri Jan 14 14:01:45 2022 @@ -1020,6 +1020,7 @@ init_patch_target(patch_target_t **patch target_content_t *content; svn_boolean_t has_text_changes = FALSE; svn_boolean_t follow_moves; + const char *tempdir_abspath; has_text_changes = ((patch->hunks && patch->hunks->nelts > 0) || patch->binary_patch); @@ -1225,8 +1226,10 @@ init_patch_target(patch_target_t **patch } /* Open a temporary file to write the patched result to. */ + SVN_ERR(svn_wc__get_tmpdir(&tempdir_abspath, wc_ctx, + target->local_abspath, scratch_pool, scratch_pool)); SVN_ERR(svn_io_open_unique_file3(&target->patched_file, - &target->patched_path, NULL, + &target->patched_path, tempdir_abspath, remove_tempfiles ? svn_io_file_del_on_pool_cleanup : svn_io_file_del_none, @@ -1238,7 +1241,7 @@ init_patch_target(patch_target_t **patch /* Open a temporary stream to write rejected hunks to. */ SVN_ERR(svn_stream_open_unique(&target->reject_stream, - &target->reject_path, NULL, + &target->reject_path, tempdir_abspath, remove_tempfiles ? svn_io_file_del_on_pool_cleanup : svn_io_file_del_none, @@ -2467,7 +2470,7 @@ send_patch_notification(const patch_targ /* Implements the callback for svn_sort__array. Puts hunks that match before hunks that do not match, puts hunks that match in order - based on postion matched, puts hunks that do not match in order + based on position matched, puts hunks that do not match in order based on original position. */ static int sort_matched_hunks(const void *a, const void *b) Modified: subversion/branches/multi-wc-format/subversion/libsvn_client/ra.c URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/subversion/libsvn_client/ra.c?rev=1897034&r1=1897033&r2=1897034&view=diff ============================================================================== --- subversion/branches/multi-wc-format/subversion/libsvn_client/ra.c (original) +++ subversion/branches/multi-wc-format/subversion/libsvn_client/ra.c Fri Jan 14 14:01:45 2022 @@ -402,8 +402,7 @@ svn_client__open_ra_session_internal(svn } } - /* If the caller allows for auto-following redirections, and the - RA->open() call above reveals a CORRECTED_URL, try the new URL. + /* If the caller allows for auto-following redirections, try the new URL. We'll do this in a loop up to some maximum number follow-and-retry attempts. */ if (corrected_url) @@ -414,12 +413,14 @@ svn_client__open_ra_session_internal(svn *corrected_url = NULL; while (attempts_left--) { - const char *corrected = NULL; + const char *corrected = NULL; /* canonicalized version */ + const char *redirect_url = NULL; /* non-canonicalized version */ /* Try to open the RA session. If this is our last attempt, don't accept corrected URLs from the RA provider. */ - SVN_ERR(svn_ra_open4(ra_session, + SVN_ERR(svn_ra_open5(ra_session, attempts_left == 0 ? NULL : &corrected, + attempts_left == 0 ? NULL : &redirect_url, base_url, uuid, cbtable, cb, ctx->config, result_pool)); @@ -441,19 +442,28 @@ svn_client__open_ra_session_internal(svn *corrected_url = corrected; /* Make sure we've not attempted this URL before. */ - if (svn_hash_gets(attempted, corrected)) + if (svn_hash_gets(attempted, redirect_url)) return svn_error_createf(SVN_ERR_CLIENT_CYCLE_DETECTED, NULL, _("Redirect cycle detected for URL '%s'"), - corrected); + redirect_url); + + /* + * Remember this redirect URL so we don't wind up in a loop. + * + * Store the non-canonicalized version of the URL. The canonicalized + * version is insufficient for loop detection because we might not get + * an exact match against URLs used by the RA protocol-layer (the URL + * used by the protocol may contain trailing slashes, for example, + * which are stripped during canonicalization). + */ + svn_hash_sets(attempted, redirect_url, (void *)1); - /* Remember this CORRECTED_URL so we don't wind up in a loop. */ - svn_hash_sets(attempted, corrected, (void *)1); base_url = corrected; } } else { - SVN_ERR(svn_ra_open4(ra_session, NULL, base_url, + SVN_ERR(svn_ra_open5(ra_session, NULL, NULL, base_url, uuid, cbtable, cb, ctx->config, result_pool)); } Modified: subversion/branches/multi-wc-format/subversion/libsvn_client/repos_diff.c URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/subversion/libsvn_client/repos_diff.c?rev=1897034&r1=1897033&r2=1897034&view=diff ============================================================================== --- subversion/branches/multi-wc-format/subversion/libsvn_client/repos_diff.c (original) +++ subversion/branches/multi-wc-format/subversion/libsvn_client/repos_diff.c Fri Jan 14 14:01:45 2022 @@ -384,7 +384,7 @@ get_file_from_ra(struct file_baton *fb, See https://issues.apache.org/jira/browse/SVN-3657#desc9 and http://svn.haxx.se/dev/archive-2010-08/0351.shtml for more details. */ -static void +static svn_error_t * remove_non_prop_changes(apr_hash_t *pristine_props, apr_array_header_t *changes) { @@ -392,7 +392,7 @@ remove_non_prop_changes(apr_hash_t *pris /* For added nodes, there is nothing to filter. */ if (apr_hash_count(pristine_props) == 0) - return; + return SVN_NO_ERROR; for (i = 0; i < changes->nelts; i++) { @@ -406,11 +406,12 @@ remove_non_prop_changes(apr_hash_t *pris if (old_val && svn_string_compare(old_val, change->value)) { /* Remove the matching change and re-check the current index */ - svn_sort__array_delete(changes, i, 1); + SVN_ERR(svn_sort__array_delete2(changes, i, 1)); i--; } } } + return SVN_NO_ERROR; } /* Get the empty file associated with the edit baton. This is cached so @@ -1010,7 +1011,7 @@ close_file(void *file_baton, } if (fb->pristine_props) - remove_non_prop_changes(fb->pristine_props, fb->propchanges); + SVN_ERR(remove_non_prop_changes(fb->pristine_props, fb->propchanges)); right_props = svn_prop__patch(fb->pristine_props, fb->propchanges, fb->pool); @@ -1083,7 +1084,7 @@ close_directory(void *dir_baton, if (db->propchanges->nelts > 0) { - remove_non_prop_changes(pristine_props, db->propchanges); + SVN_ERR(remove_non_prop_changes(pristine_props, db->propchanges)); } if (db->propchanges->nelts > 0 || db->added) Modified: subversion/branches/multi-wc-format/subversion/libsvn_client/revert.c URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/subversion/libsvn_client/revert.c?rev=1897034&r1=1897033&r2=1897034&view=diff ============================================================================== --- subversion/branches/multi-wc-format/subversion/libsvn_client/revert.c (original) +++ subversion/branches/multi-wc-format/subversion/libsvn_client/revert.c Fri Jan 14 14:01:45 2022 @@ -57,24 +57,12 @@ struct revert_with_write_lock_baton { /* (Note: All arguments are in the baton above.) - Attempt to revert LOCAL_ABSPATH. + Attempt to revert LOCAL_ABSPATH by calling svn_wc_revert6(), which + see for further details. - If DEPTH is svn_depth_empty, revert just the properties on the - directory; else if svn_depth_files, revert the properties and any - files immediately under the directory; else if - svn_depth_immediates, revert all of the preceding plus properties - on immediate subdirectories; else if svn_depth_infinity, revert - path and everything under it fully recursively. - - CHANGELISTS is an array of const char * changelist names, used as a - restrictive filter on items reverted; that is, don't revert any - item unless it's a member of one of those changelists. If - CHANGELISTS is empty (or altogether NULL), no changelist filtering occurs. - - Consult CTX to determine whether or not to revert timestamp to the - time of last commit ('use-commit-times = yes'). - - If PATH is unversioned, return SVN_ERR_UNVERSIONED_RESOURCE. */ + If the target isn't versioned, send a 'skip' notification and return + no error. + */ static svn_error_t * revert(void *baton, apr_pool_t *result_pool, apr_pool_t *scratch_pool) {
