merge.c revision 289166
1/* 2 * merge.c: merging 3 * 4 * ==================================================================== 5 * Licensed to the Apache Software Foundation (ASF) under one 6 * or more contributor license agreements. See the NOTICE file 7 * distributed with this work for additional information 8 * regarding copyright ownership. The ASF licenses this file 9 * to you under the Apache License, Version 2.0 (the 10 * "License"); you may not use this file except in compliance 11 * with the License. You may obtain a copy of the License at 12 * 13 * http://www.apache.org/licenses/LICENSE-2.0 14 * 15 * Unless required by applicable law or agreed to in writing, 16 * software distributed under the License is distributed on an 17 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 18 * KIND, either express or implied. See the License for the 19 * specific language governing permissions and limitations 20 * under the License. 21 * ==================================================================== 22 */ 23 24/* ==================================================================== */ 25 26 27 28/*** Includes ***/ 29 30#include <assert.h> 31#include <apr_strings.h> 32#include <apr_tables.h> 33#include <apr_hash.h> 34#include "svn_types.h" 35#include "svn_hash.h" 36#include "svn_wc.h" 37#include "svn_delta.h" 38#include "svn_diff.h" 39#include "svn_mergeinfo.h" 40#include "svn_client.h" 41#include "svn_string.h" 42#include "svn_error.h" 43#include "svn_dirent_uri.h" 44#include "svn_path.h" 45#include "svn_io.h" 46#include "svn_utf.h" 47#include "svn_pools.h" 48#include "svn_config.h" 49#include "svn_props.h" 50#include "svn_time.h" 51#include "svn_sorts.h" 52#include "svn_subst.h" 53#include "svn_ra.h" 54#include "client.h" 55#include "mergeinfo.h" 56 57#include "private/svn_opt_private.h" 58#include "private/svn_wc_private.h" 59#include "private/svn_mergeinfo_private.h" 60#include "private/svn_fspath.h" 61#include "private/svn_ra_private.h" 62#include "private/svn_client_private.h" 63#include "private/svn_subr_private.h" 64 65#include "svn_private_config.h" 66 67 68/*-----------------------------------------------------------------------*/ 69 70/* MERGEINFO MERGE SOURCE NORMALIZATION 71 * 72 * Nearly any helper function herein that accepts two URL/revision 73 * pairs (or equivalent struct merge_source_t) expects one of two things 74 * to be true: 75 * 76 * 1. that mergeinfo is not being recorded at all for this 77 * operation, or 78 * 79 * 2. that the pairs represent two locations along a single line 80 * of version history such that there are no copies in the 81 * history of the object between the locations when treating 82 * the oldest of the two locations as non-inclusive. In other 83 * words, if there is a copy at all between them, there is only 84 * one copy and its source was the oldest of the two locations. 85 * 86 * We use svn_ra_get_location_segments() to split a given range of 87 * revisions across an object's history into several which obey these 88 * rules. For example, an extract from the log of Subversion's own 89 * /subversion/tags/1.4.5 directory shows the following copies between 90 * r859500 and r866500 (omitting the '/subversion' prefix for clarity): 91 * 92 * r859598: 93 * A /branches/1.4.x (from /trunk:859597) 94 * 95 * r865417: 96 * A /tags/1.4.4 (from /branches/1.4.x:865262) 97 * # Notice that this copy leaves a gap between 865262 and 865417. 98 * 99 * r866420: 100 * A /branches/1.4.5 (from /tags/1.4.4:866419) 101 * 102 * r866425: 103 * D /branches/1.4.5 104 * A /tags/1.4.5 (from /branches/1.4.5:866424) 105 * 106 * In graphical form: 107 * 108 * 859500 859597 865262 866419 866424 866500 109 * . . . . . . 110 * trunk ------------------------------------------------ 111 * \ . . . 112 * branches/1.4.x A------------------------------------- 113 * . \______ . . 114 * . \ . . 115 * tags/1.4.4 . A----------------------- 116 * . . \ . 117 * branches/1.4.5 . . A------D 118 * . . . \. 119 * tags/1.4.5 . . . A--------- 120 * . . . . 121 * 859598 865417 866420 866425 122 * 123 * A merge of the difference between r859500 and r866500 of this directory 124 * gets split into sequential merges of the following location pairs. 125 * 126 * 859500 859597 865262 865416 866419 866424 866500 127 * . . . . . . . 128 * trunk (======] . . . . . 129 * . . . . . 130 * trunk ( . . . . . 131 * branches/1.4.x ======] . . . . 132 * . . . . 133 * branches/1.4.x ( . . . . 134 * tags/1.4.4 =============] . . 135 * implicit_src_gap (======] . . . 136 * . . . 137 * tags/1.4.4 ( . . 138 * branches/1.4.5 ======] . 139 * . . 140 * branches/1.4.5 ( . 141 * tags/1.4.5 ======] 142 * 143 * which are represented in merge_source_t as: 144 * 145 * [/trunk:859500, /trunk:859597] 146 * (recorded in svn:mergeinfo as /trunk:859501-859597) 147 * 148 * [/trunk:859597, /branches/1.4.x:865262] 149 * (recorded in svn:mergeinfo as /branches/1.4.x:859598-865262) 150 * 151 * [/branches/1.4.x:865262, /tags/1.4.4@866419] 152 * (recorded in svn:mergeinfo as /tags/1.4.4:865263-866419) 153 * (and there is a gap, the revision range [865262, 865416]) 154 * 155 * [/tags/1.4.4@866419, /branches/1.4.5@866424] 156 * (recorded in svn:mergeinfo as /branches/1.4.5:866420-866424) 157 * 158 * [/branches/1.4.5@866424, /tags/1.4.5@866500] 159 * (recorded in svn:mergeinfo as /tags/1.4.5:866425-866500) 160 * 161 * Our helper functions would then operate on one of these location 162 * pairs at a time. 163 */ 164 165/* WHICH SVN_CLIENT_MERGE* API DO I WANT? 166 * 167 * libsvn_client has three public merge APIs; they are all wrappers 168 * around the do_merge engine. Which one to use depends on the number 169 * of URLs passed as arguments and whether or not specific merge 170 * ranges (-c/-r) are specified. 171 * 172 * 1 URL 2 URLs 173 * +----+--------------------------------+---------------------+ 174 * | -c | mergeinfo-driven | | 175 * | or | cherrypicking | | 176 * | -r | (svn_client_merge_peg) | | 177 * |----+--------------------------------+ | 178 * | | mergeinfo-driven | unsupported | 179 * | | 'cherry harvest', i.e. merge | | 180 * | | all revisions from URL that | | 181 * | no | have not already been merged | | 182 * | -c | (svn_client_merge_peg) | | 183 * | or +--------------------------------+---------------------+ 184 * | -r | mergeinfo-driven | mergeinfo-writing | 185 * | | whole-branch | diff-and-apply | 186 * | | heuristic merge | (svn_client_merge) | 187 * | | (svn_client_merge_reintegrate) | | 188 * +----+--------------------------------+---------------------+ 189 * 190 * 191 */ 192 193/* THE CHILDREN_WITH_MERGEINFO ARRAY 194 * 195 * Many of the helper functions in this file pass around an 196 * apr_array_header_t *CHILDREN_WITH_MERGEINFO. This is a depth first 197 * sorted array filled with svn_client__merge_path_t * describing the 198 * merge target and any of its subtrees which have explicit mergeinfo 199 * or otherwise need special attention during a merge. 200 * 201 * During mergeinfo unaware merges, CHILDREN_WITH_MERGEINFO contains 202 * contains only one element (added by do_mergeinfo_unaware_dir_merge) 203 * describing a contiguous range to be merged to the WC merge target. 204 * 205 * During mergeinfo aware merges CHILDREN_WITH_MERGEINFO is created 206 * by get_mergeinfo_paths() and outside of that function and its helpers 207 * should always meet the criteria dictated in get_mergeinfo_paths()'s doc 208 * string. The elements of CHILDREN_WITH_MERGEINFO should never be NULL. 209 * 210 * For clarification on mergeinfo aware vs. mergeinfo unaware merges, see 211 * the doc string for HONOR_MERGEINFO(). 212 */ 213 214 215/*-----------------------------------------------------------------------*/ 216 217/*** Repos-Diff Editor Callbacks ***/ 218 219/* */ 220typedef struct merge_source_t 221{ 222 /* "left" side URL and revision (inclusive iff youngest) */ 223 const svn_client__pathrev_t *loc1; 224 225 /* "right" side URL and revision (inclusive iff youngest) */ 226 const svn_client__pathrev_t *loc2; 227 228 /* True iff LOC1 is an ancestor of LOC2 or vice-versa (history-wise). */ 229 svn_boolean_t ancestral; 230} merge_source_t; 231 232/* Description of the merge target root node (a WC working node) */ 233typedef struct merge_target_t 234{ 235 /* Absolute path to the WC node */ 236 const char *abspath; 237 238 /* The repository location of the base node of the target WC. If the node 239 * is locally added, then URL & REV are NULL & SVN_INVALID_REVNUM. 240 * REPOS_ROOT_URL and REPOS_UUID are always valid. */ 241 svn_client__pathrev_t loc; 242 243} merge_target_t; 244 245typedef struct merge_cmd_baton_t { 246 svn_boolean_t force_delete; /* Delete a file/dir even if modified */ 247 svn_boolean_t dry_run; 248 svn_boolean_t record_only; /* Whether to merge only mergeinfo 249 differences. */ 250 svn_boolean_t same_repos; /* Whether the merge source repository 251 is the same repository as the 252 target. Defaults to FALSE if DRY_RUN 253 is TRUE.*/ 254 svn_boolean_t mergeinfo_capable; /* Whether the merge source server 255 is capable of Merge Tracking. */ 256 svn_boolean_t ignore_mergeinfo; /* Don't honor mergeinfo; see 257 doc string of do_merge(). FALSE if 258 MERGE_SOURCE->ancestral is FALSE. */ 259 svn_boolean_t diff_ignore_ancestry; /* Diff unrelated nodes as if related; see 260 doc string of do_merge(). FALSE if 261 MERGE_SOURCE->ancestral is FALSE. */ 262 svn_boolean_t reintegrate_merge; /* Whether this is a --reintegrate 263 merge or not. */ 264 const merge_target_t *target; /* Description of merge target node */ 265 266 /* The left and right URLs and revs. The value of this field changes to 267 reflect the merge_source_t *currently* being merged by do_merge(). */ 268 merge_source_t merge_source; 269 270 /* Rangelist containing single range which describes the gap, if any, 271 in the natural history of the merge source currently being processed. 272 See http://subversion.tigris.org/issues/show_bug.cgi?id=3432. 273 Updated during each call to do_directory_merge(). May be NULL if there 274 is no gap. */ 275 svn_rangelist_t *implicit_src_gap; 276 277 svn_client_ctx_t *ctx; /* Client context for callbacks, etc. */ 278 279 /* The list of any paths which remained in conflict after a 280 resolution attempt was made. We track this in-memory, rather 281 than just using WC entry state, since the latter doesn't help us 282 when in dry_run mode. 283 ### And because we only want to resolve conflicts that were 284 generated by this merge, not pre-existing ones? */ 285 apr_hash_t *conflicted_paths; 286 287 /* A list of absolute paths which had no explicit mergeinfo prior to the 288 merge but got explicit mergeinfo added by the merge. This is populated 289 by merge_change_props() and is allocated in POOL so it is subject to the 290 lifetime limitations of POOL. Is NULL if no paths are found which 291 meet the criteria or DRY_RUN is true. */ 292 apr_hash_t *paths_with_new_mergeinfo; 293 294 /* A list of absolute paths whose mergeinfo doesn't need updating after 295 the merge. This can be caused by the removal of mergeinfo by the merge 296 or by deleting the node itself. This is populated by merge_change_props() 297 and the delete callbacks and is allocated in POOL so it is subject to the 298 lifetime limitations of POOL. Is NULL if no paths are found which 299 meet the criteria or DRY_RUN is true. */ 300 apr_hash_t *paths_with_deleted_mergeinfo; 301 302 /* The list of absolute skipped paths, which should be examined and 303 cleared after each invocation of the callback. The paths 304 are absolute. Is NULL if MERGE_B->MERGE_SOURCE->ancestral and 305 MERGE_B->REINTEGRATE_MERGE are both false. */ 306 apr_hash_t *skipped_abspaths; 307 308 /* The list of absolute merged paths. Unused if MERGE_B->MERGE_SOURCE->ancestral 309 and MERGE_B->REINTEGRATE_MERGE are both false. */ 310 apr_hash_t *merged_abspaths; 311 312 /* A hash of (const char *) absolute WC paths mapped to the same which 313 represent the roots of subtrees added by the merge. */ 314 apr_hash_t *added_abspaths; 315 316 /* A list of tree conflict victim absolute paths which may be NULL. */ 317 apr_hash_t *tree_conflicted_abspaths; 318 319 /* The diff3_cmd in ctx->config, if any, else null. We could just 320 extract this as needed, but since more than one caller uses it, 321 we just set it up when this baton is created. */ 322 const char *diff3_cmd; 323 const apr_array_header_t *merge_options; 324 325 /* Array of file extension patterns to preserve as extensions in 326 generated conflict files. */ 327 const apr_array_header_t *ext_patterns; 328 329 /* RA sessions used throughout a merge operation. Opened/re-parented 330 as needed. 331 332 NOTE: During the actual merge editor drive, RA_SESSION1 is used 333 for the primary editing and RA_SESSION2 for fetching additional 334 information -- as necessary -- from the repository. So during 335 this phase of the merge, you *must not* reparent RA_SESSION1; use 336 (temporarily reparenting if you must) RA_SESSION2 instead. */ 337 svn_ra_session_t *ra_session1; 338 svn_ra_session_t *ra_session2; 339 340 /* During the merge, *USE_SLEEP is set to TRUE if a sleep will be required 341 afterwards to ensure timestamp integrity, or unchanged if not. */ 342 svn_boolean_t *use_sleep; 343 344 /* Pool which has a lifetime limited to one iteration over a given 345 merge source, i.e. it is cleared on every call to do_directory_merge() 346 or do_file_merge() in do_merge(). */ 347 apr_pool_t *pool; 348 349 350 /* State for notify_merge_begin() */ 351 struct notify_begin_state_t 352 { 353 /* Cache of which abspath was last notified. */ 354 const char *last_abspath; 355 356 /* Reference to the one-and-only CHILDREN_WITH_MERGEINFO (see global 357 comment) or a similar list for single-file-merges */ 358 const apr_array_header_t *nodes_with_mergeinfo; 359 } notify_begin; 360 361} merge_cmd_baton_t; 362 363 364/* Return TRUE iff we should be taking account of mergeinfo in deciding what 365 changes to merge, for the merge described by MERGE_B. Specifically, that 366 is if the merge source server is capable of merge tracking, the left-side 367 merge source is an ancestor of the right-side (or vice-versa), the merge 368 source is in the same repository as the merge target, and we are not 369 ignoring mergeinfo. */ 370#define HONOR_MERGEINFO(merge_b) ((merge_b)->mergeinfo_capable \ 371 && (merge_b)->merge_source.ancestral \ 372 && (merge_b)->same_repos \ 373 && (! (merge_b)->ignore_mergeinfo)) 374 375 376/* Return TRUE iff we should be recording mergeinfo for the merge described 377 by MERGE_B. Specifically, that is if we are honoring mergeinfo and the 378 merge is not a dry run. */ 379#define RECORD_MERGEINFO(merge_b) (HONOR_MERGEINFO(merge_b) \ 380 && !(merge_b)->dry_run) 381 382 383/*-----------------------------------------------------------------------*/ 384 385/*** Utilities ***/ 386 387/* Return TRUE iff the session URL of RA_SESSION is equal to URL. Useful in 388 * asserting preconditions. */ 389static svn_boolean_t 390session_url_is(svn_ra_session_t *ra_session, 391 const char *url, 392 apr_pool_t *scratch_pool) 393{ 394 const char *session_url; 395 svn_error_t *err 396 = svn_ra_get_session_url(ra_session, &session_url, scratch_pool); 397 398 SVN_ERR_ASSERT_NO_RETURN(! err); 399 return strcmp(url, session_url) == 0; 400} 401 402/* Return a new merge_source_t structure, allocated in RESULT_POOL, 403 * initialized with deep copies of LOC1 and LOC2 and ANCESTRAL. */ 404static merge_source_t * 405merge_source_create(const svn_client__pathrev_t *loc1, 406 const svn_client__pathrev_t *loc2, 407 svn_boolean_t ancestral, 408 apr_pool_t *result_pool) 409{ 410 merge_source_t *s 411 = apr_palloc(result_pool, sizeof(*s)); 412 413 s->loc1 = svn_client__pathrev_dup(loc1, result_pool); 414 s->loc2 = svn_client__pathrev_dup(loc2, result_pool); 415 s->ancestral = ancestral; 416 return s; 417} 418 419/* Return a deep copy of SOURCE, allocated in RESULT_POOL. */ 420static merge_source_t * 421merge_source_dup(const merge_source_t *source, 422 apr_pool_t *result_pool) 423{ 424 merge_source_t *s = apr_palloc(result_pool, sizeof(*s)); 425 426 s->loc1 = svn_client__pathrev_dup(source->loc1, result_pool); 427 s->loc2 = svn_client__pathrev_dup(source->loc2, result_pool); 428 s->ancestral = source->ancestral; 429 return s; 430} 431 432/* Return SVN_ERR_UNSUPPORTED_FEATURE if URL is not inside the repository 433 of LOCAL_ABSPATH. Use SCRATCH_POOL for temporary allocations. */ 434static svn_error_t * 435check_repos_match(const merge_target_t *target, 436 const char *local_abspath, 437 const char *url, 438 apr_pool_t *scratch_pool) 439{ 440 if (!svn_uri__is_ancestor(target->loc.repos_root_url, url)) 441 return svn_error_createf( 442 SVN_ERR_UNSUPPORTED_FEATURE, NULL, 443 _("URL '%s' of '%s' is not in repository '%s'"), 444 url, svn_dirent_local_style(local_abspath, scratch_pool), 445 target->loc.repos_root_url); 446 447 return SVN_NO_ERROR; 448} 449 450/* Return TRUE iff the repository of LOCATION1 is the same as 451 * that of LOCATION2. If STRICT_URLS is true, the URLs must 452 * match (and the UUIDs, just to be sure), otherwise just the UUIDs must 453 * match and the URLs can differ (a common case is http versus https). */ 454static svn_boolean_t 455is_same_repos(const svn_client__pathrev_t *location1, 456 const svn_client__pathrev_t *location2, 457 svn_boolean_t strict_urls) 458{ 459 if (strict_urls) 460 return (strcmp(location1->repos_root_url, location2->repos_root_url) == 0 461 && strcmp(location1->repos_uuid, location2->repos_uuid) == 0); 462 else 463 return (strcmp(location1->repos_uuid, location2->repos_uuid) == 0); 464} 465 466/* If the repository identified of LOCATION1 is not the same as that 467 * of LOCATION2, throw a SVN_ERR_CLIENT_UNRELATED_RESOURCES 468 * error mentioning PATH1 and PATH2. For STRICT_URLS, see is_same_repos(). 469 */ 470static svn_error_t * 471check_same_repos(const svn_client__pathrev_t *location1, 472 const char *path1, 473 const svn_client__pathrev_t *location2, 474 const char *path2, 475 svn_boolean_t strict_urls, 476 apr_pool_t *scratch_pool) 477{ 478 if (! is_same_repos(location1, location2, strict_urls)) 479 return svn_error_createf(SVN_ERR_CLIENT_UNRELATED_RESOURCES, NULL, 480 _("'%s' must be from the same repository as " 481 "'%s'"), path1, path2); 482 return SVN_NO_ERROR; 483} 484 485/* Store LOCAL_ABSPATH in PATH_HASH after duplicating it into the pool 486 containing PATH_HASH. */ 487static APR_INLINE void 488store_path(apr_hash_t *path_hash, const char *local_abspath) 489{ 490 const char *dup_path = apr_pstrdup(apr_hash_pool_get(path_hash), 491 local_abspath); 492 493 svn_hash_sets(path_hash, dup_path, dup_path); 494} 495 496/* Store LOCAL_ABSPATH in *PATH_HASH_P after duplicating it into the pool 497 containing *PATH_HASH_P. If *PATH_HASH_P is NULL, then first set 498 *PATH_HASH_P to a new hash allocated from POOL. */ 499static APR_INLINE void 500alloc_and_store_path(apr_hash_t **path_hash_p, 501 const char *local_abspath, 502 apr_pool_t *pool) 503{ 504 if (! *path_hash_p) 505 *path_hash_p = apr_hash_make(pool); 506 store_path(*path_hash_p, local_abspath); 507} 508 509/* Return whether any WC path was put in conflict by the merge 510 operation corresponding to MERGE_B. */ 511static APR_INLINE svn_boolean_t 512is_path_conflicted_by_merge(merge_cmd_baton_t *merge_b) 513{ 514 return (merge_b->conflicted_paths && 515 apr_hash_count(merge_b->conflicted_paths) > 0); 516} 517 518/* Return a state indicating whether the WC metadata matches the 519 * node kind on disk of the local path LOCAL_ABSPATH. 520 * Use MERGE_B to determine the dry-run details; particularly, if a dry run 521 * noted that it deleted this path, assume matching node kinds (as if both 522 * kinds were svn_node_none). 523 * 524 * - Return svn_wc_notify_state_inapplicable if the node kind matches. 525 * - Return 'obstructed' if there is a node on disk where none or a 526 * different kind is expected, or if the disk node cannot be read. 527 * - Return 'missing' if there is no node on disk but one is expected. 528 * Also return 'missing' for server-excluded nodes (not here due to 529 * authz or other reasons determined by the server). 530 * 531 * Optionally return a bit more info for interested users. 532 **/ 533static svn_error_t * 534perform_obstruction_check(svn_wc_notify_state_t *obstruction_state, 535 svn_boolean_t *deleted, 536 svn_boolean_t *excluded, 537 svn_node_kind_t *kind, 538 svn_depth_t *parent_depth, 539 const merge_cmd_baton_t *merge_b, 540 const char *local_abspath, 541 apr_pool_t *scratch_pool) 542{ 543 svn_wc_context_t *wc_ctx = merge_b->ctx->wc_ctx; 544 svn_node_kind_t wc_kind; 545 svn_boolean_t check_root; 546 547 SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath)); 548 549 *obstruction_state = svn_wc_notify_state_inapplicable; 550 551 if (deleted) 552 *deleted = FALSE; 553 if (kind) 554 *kind = svn_node_none; 555 556 if (kind == NULL) 557 kind = &wc_kind; 558 559 check_root = ! strcmp(local_abspath, merge_b->target->abspath); 560 561 SVN_ERR(svn_wc__check_for_obstructions(obstruction_state, 562 kind, 563 deleted, 564 excluded, 565 parent_depth, 566 wc_ctx, local_abspath, 567 check_root, 568 scratch_pool)); 569 return SVN_NO_ERROR; 570} 571 572/* Create *LEFT and *RIGHT conflict versions for conflict victim 573 * at VICTIM_ABSPATH, with kind NODE_KIND, using information obtained 574 * from MERGE_SOURCE and TARGET. 575 * Allocate returned conflict versions in RESULT_POOL. */ 576static svn_error_t * 577make_conflict_versions(const svn_wc_conflict_version_t **left, 578 const svn_wc_conflict_version_t **right, 579 const char *victim_abspath, 580 svn_node_kind_t node_kind, 581 const merge_source_t *merge_source, 582 const merge_target_t *target, 583 apr_pool_t *result_pool, 584 apr_pool_t *scratch_pool) 585{ 586 const char *child = svn_dirent_skip_ancestor(target->abspath, 587 victim_abspath); 588 const char *left_relpath, *right_relpath; 589 590 SVN_ERR_ASSERT(child != NULL); 591 left_relpath = svn_client__pathrev_relpath(merge_source->loc1, 592 scratch_pool); 593 right_relpath = svn_client__pathrev_relpath(merge_source->loc2, 594 scratch_pool); 595 596 *left = svn_wc_conflict_version_create2( 597 merge_source->loc1->repos_root_url, 598 merge_source->loc1->repos_uuid, 599 svn_relpath_join(left_relpath, child, scratch_pool), 600 merge_source->loc1->rev, node_kind, result_pool); 601 602 *right = svn_wc_conflict_version_create2( 603 merge_source->loc2->repos_root_url, 604 merge_source->loc2->repos_uuid, 605 svn_relpath_join(right_relpath, child, scratch_pool), 606 merge_source->loc2->rev, node_kind, result_pool); 607 608 return SVN_NO_ERROR; 609} 610 611/* Helper for filter_self_referential_mergeinfo() 612 613 *MERGEINFO is a non-empty, non-null collection of mergeinfo. 614 615 Remove all mergeinfo from *MERGEINFO that describes revision ranges 616 greater than REVISION. Put a copy of any removed mergeinfo, allocated 617 in POOL, into *YOUNGER_MERGEINFO. 618 619 If no mergeinfo is removed from *MERGEINFO then *YOUNGER_MERGEINFO is set 620 to NULL. If all mergeinfo is removed from *MERGEINFO then *MERGEINFO is 621 set to NULL. 622 */ 623static svn_error_t* 624split_mergeinfo_on_revision(svn_mergeinfo_t *younger_mergeinfo, 625 svn_mergeinfo_t *mergeinfo, 626 svn_revnum_t revision, 627 apr_pool_t *pool) 628{ 629 apr_hash_index_t *hi; 630 apr_pool_t *iterpool = svn_pool_create(pool); 631 632 *younger_mergeinfo = NULL; 633 for (hi = apr_hash_first(pool, *mergeinfo); hi; hi = apr_hash_next(hi)) 634 { 635 int i; 636 const char *merge_source_path = svn__apr_hash_index_key(hi); 637 svn_rangelist_t *rangelist = svn__apr_hash_index_val(hi); 638 639 svn_pool_clear(iterpool); 640 641 for (i = 0; i < rangelist->nelts; i++) 642 { 643 svn_merge_range_t *range = 644 APR_ARRAY_IDX(rangelist, i, svn_merge_range_t *); 645 if (range->end <= revision) 646 { 647 /* This entirely of this range is as old or older than 648 REVISION, so leave it in *MERGEINFO. */ 649 continue; 650 } 651 else 652 { 653 /* Since the rangelists in svn_mergeinfo_t's are sorted in 654 increasing order we know that part or all of *this* range 655 and *all* of the remaining ranges in *RANGELIST are younger 656 than REVISION. Remove the younger rangelists from 657 *MERGEINFO and put them in *YOUNGER_MERGEINFO. */ 658 int j; 659 svn_rangelist_t *younger_rangelist = 660 apr_array_make(pool, 1, sizeof(svn_merge_range_t *)); 661 662 for (j = i; j < rangelist->nelts; j++) 663 { 664 svn_merge_range_t *younger_range = svn_merge_range_dup( 665 APR_ARRAY_IDX(rangelist, j, svn_merge_range_t *), pool); 666 667 /* REVISION might intersect with the first range where 668 range->end > REVISION. If that is the case then split 669 the current range into two, putting the younger half 670 into *YOUNGER_MERGEINFO and leaving the older half in 671 *MERGEINFO. */ 672 if (j == i && range->start + 1 <= revision) 673 younger_range->start = range->end = revision; 674 675 APR_ARRAY_PUSH(younger_rangelist, svn_merge_range_t *) = 676 younger_range; 677 } 678 679 /* So far we've only been manipulating rangelists, now we 680 actually create *YOUNGER_MERGEINFO and then remove the older 681 ranges from *MERGEINFO */ 682 if (!(*younger_mergeinfo)) 683 *younger_mergeinfo = apr_hash_make(pool); 684 svn_hash_sets(*younger_mergeinfo, merge_source_path, 685 younger_rangelist); 686 SVN_ERR(svn_mergeinfo_remove2(mergeinfo, *younger_mergeinfo, 687 *mergeinfo, TRUE, pool, iterpool)); 688 break; /* ...out of for (i = 0; i < rangelist->nelts; i++) */ 689 } 690 } 691 } 692 693 svn_pool_destroy(iterpool); 694 695 return SVN_NO_ERROR; 696} 697 698 699/* Make a copy of PROPCHANGES (array of svn_prop_t) into *TRIMMED_PROPCHANGES, 700 omitting any svn:mergeinfo changes. */ 701static svn_error_t * 702omit_mergeinfo_changes(apr_array_header_t **trimmed_propchanges, 703 const apr_array_header_t *propchanges, 704 apr_pool_t *result_pool) 705{ 706 int i; 707 708 *trimmed_propchanges = apr_array_make(result_pool, 709 propchanges->nelts, 710 sizeof(svn_prop_t)); 711 712 for (i = 0; i < propchanges->nelts; ++i) 713 { 714 const svn_prop_t *change = &APR_ARRAY_IDX(propchanges, i, svn_prop_t); 715 716 /* If this property is not svn:mergeinfo, then copy it. */ 717 if (strcmp(change->name, SVN_PROP_MERGEINFO) != 0) 718 APR_ARRAY_PUSH(*trimmed_propchanges, svn_prop_t) = *change; 719 } 720 721 return SVN_NO_ERROR; 722} 723 724 725/* Helper for merge_props_changed(). 726 727 *PROPS is an array of svn_prop_t structures representing regular properties 728 to be added to the working copy TARGET_ABSPATH. 729 730 The merge source and target are assumed to be in the same repository. 731 732 Filter out mergeinfo property additions to TARGET_ABSPATH when 733 those additions refer to the same line of history as TARGET_ABSPATH as 734 described below. 735 736 Examine the added mergeinfo, looking at each range (or single rev) 737 of each source path. If a source_path/range refers to the same line of 738 history as TARGET_ABSPATH (pegged at its base revision), then filter out 739 that range. If the entire rangelist for a given path is filtered then 740 filter out the path as well. 741 742 RA_SESSION is an open RA session to the repository 743 in which both the source and target live, else RA_SESSION is not used. It 744 may be temporarily reparented as needed by this function. 745 746 Use CTX for any further client operations. 747 748 If any filtering occurs, set outgoing *PROPS to a shallow copy (allocated 749 in POOL) of incoming *PROPS minus the filtered mergeinfo. */ 750static svn_error_t * 751filter_self_referential_mergeinfo(apr_array_header_t **props, 752 const char *target_abspath, 753 svn_ra_session_t *ra_session, 754 svn_client_ctx_t *ctx, 755 apr_pool_t *pool) 756{ 757 apr_array_header_t *adjusted_props; 758 int i; 759 apr_pool_t *iterpool; 760 svn_boolean_t is_copy; 761 const char *repos_relpath; 762 svn_client__pathrev_t target_base; 763 764 /* If PATH itself has been added there is no need to filter. */ 765 SVN_ERR(svn_wc__node_get_origin(&is_copy, &target_base.rev, &repos_relpath, 766 &target_base.repos_root_url, 767 &target_base.repos_uuid, NULL, 768 ctx->wc_ctx, target_abspath, FALSE, 769 pool, pool)); 770 771 if (is_copy || !repos_relpath) 772 return SVN_NO_ERROR; /* A copy or a local addition */ 773 774 target_base.url = svn_path_url_add_component2(target_base.repos_root_url, 775 repos_relpath, pool); 776 777 adjusted_props = apr_array_make(pool, (*props)->nelts, sizeof(svn_prop_t)); 778 iterpool = svn_pool_create(pool); 779 for (i = 0; i < (*props)->nelts; ++i) 780 { 781 svn_prop_t *prop = &APR_ARRAY_IDX((*props), i, svn_prop_t); 782 783 svn_mergeinfo_t mergeinfo, younger_mergeinfo; 784 svn_mergeinfo_t filtered_mergeinfo = NULL; 785 svn_mergeinfo_t filtered_younger_mergeinfo = NULL; 786 svn_error_t *err; 787 788 /* If this property isn't mergeinfo or is NULL valued (i.e. prop removal) 789 or empty mergeinfo it does not require any special handling. There 790 is nothing to filter out of empty mergeinfo and the concept of 791 filtering doesn't apply if we are trying to remove mergeinfo 792 entirely. */ 793 if ((strcmp(prop->name, SVN_PROP_MERGEINFO) != 0) 794 || (! prop->value) /* Removal of mergeinfo */ 795 || (! prop->value->len)) /* Empty mergeinfo */ 796 { 797 APR_ARRAY_PUSH(adjusted_props, svn_prop_t) = *prop; 798 continue; 799 } 800 801 svn_pool_clear(iterpool); 802 803 /* Non-empty mergeinfo; filter self-referential mergeinfo out. */ 804 805 /* Parse the incoming mergeinfo to allow easier manipulation. */ 806 err = svn_mergeinfo_parse(&mergeinfo, prop->value->data, iterpool); 807 808 if (err) 809 { 810 /* Issue #3896: If we can't parse it, we certainly can't 811 filter it. */ 812 if (err->apr_err == SVN_ERR_MERGEINFO_PARSE_ERROR) 813 { 814 svn_error_clear(err); 815 APR_ARRAY_PUSH(adjusted_props, svn_prop_t) = *prop; 816 continue; 817 } 818 else 819 { 820 return svn_error_trace(err); 821 } 822 } 823 824 /* The working copy target PATH is at BASE_REVISION. Divide the 825 incoming mergeinfo into two groups. One where all revision ranges 826 are as old or older than BASE_REVISION and one where all revision 827 ranges are younger. 828 829 Note: You may be wondering why we do this. 830 831 For the incoming mergeinfo "older" than target's base revision we 832 can filter out self-referential mergeinfo efficiently using 833 svn_client__get_history_as_mergeinfo(). We simply look at PATH's 834 natural history as mergeinfo and remove that from any incoming 835 mergeinfo. 836 837 For mergeinfo "younger" than the base revision we can't use 838 svn_ra_get_location_segments() to look into PATH's future 839 history. Instead we must use svn_client__repos_locations() and 840 look at each incoming source/range individually and see if PATH 841 at its base revision and PATH at the start of the incoming range 842 exist on the same line of history. If they do then we can filter 843 out the incoming range. But since we have to do this for each 844 range there is a substantial performance penalty to pay if the 845 incoming ranges are not contiguous, i.e. we call 846 svn_client__repos_locations for each discrete range and incur 847 the cost of a roundtrip communication with the repository. */ 848 SVN_ERR(split_mergeinfo_on_revision(&younger_mergeinfo, 849 &mergeinfo, 850 target_base.rev, 851 iterpool)); 852 853 /* Filter self-referential mergeinfo from younger_mergeinfo. */ 854 if (younger_mergeinfo) 855 { 856 apr_hash_index_t *hi; 857 const char *merge_source_root_url; 858 859 SVN_ERR(svn_ra_get_repos_root2(ra_session, 860 &merge_source_root_url, iterpool)); 861 862 for (hi = apr_hash_first(iterpool, younger_mergeinfo); 863 hi; hi = apr_hash_next(hi)) 864 { 865 int j; 866 const char *source_path = svn__apr_hash_index_key(hi); 867 svn_rangelist_t *rangelist = svn__apr_hash_index_val(hi); 868 const char *merge_source_url; 869 svn_rangelist_t *adjusted_rangelist = 870 apr_array_make(iterpool, 0, sizeof(svn_merge_range_t *)); 871 872 merge_source_url = 873 svn_path_url_add_component2(merge_source_root_url, 874 source_path + 1, iterpool); 875 876 for (j = 0; j < rangelist->nelts; j++) 877 { 878 svn_error_t *err2; 879 svn_client__pathrev_t *start_loc; 880 svn_merge_range_t *range = 881 APR_ARRAY_IDX(rangelist, j, svn_merge_range_t *); 882 883 /* Because the merge source normalization code 884 ensures mergeinfo refers to real locations on 885 the same line of history, there's no need to 886 look at the whole range, just the start. */ 887 888 /* Check if PATH@BASE_REVISION exists at 889 RANGE->START on the same line of history. 890 (start+1 because RANGE->start is not inclusive.) */ 891 err2 = svn_client__repos_location(&start_loc, ra_session, 892 &target_base, 893 range->start + 1, 894 ctx, iterpool, iterpool); 895 if (err2) 896 { 897 if (err2->apr_err == SVN_ERR_CLIENT_UNRELATED_RESOURCES 898 || err2->apr_err == SVN_ERR_FS_NOT_FOUND 899 || err2->apr_err == SVN_ERR_FS_NO_SUCH_REVISION) 900 { 901 /* PATH@BASE_REVISION didn't exist at 902 RANGE->START + 1 or is unrelated to the 903 resource PATH@RANGE->START. Some of the 904 requested revisions may not even exist in 905 the repository; a real possibility since 906 mergeinfo is hand editable. In all of these 907 cases clear and ignore the error and don't 908 do any filtering. 909 910 Note: In this last case it is possible that 911 we will allow self-referential mergeinfo to 912 be applied, but fixing it here is potentially 913 very costly in terms of finding what part of 914 a range is actually valid. Simply allowing 915 the merge to proceed without filtering the 916 offending range seems the least worst 917 option. */ 918 svn_error_clear(err2); 919 err2 = NULL; 920 APR_ARRAY_PUSH(adjusted_rangelist, 921 svn_merge_range_t *) = range; 922 } 923 else 924 { 925 return svn_error_trace(err2); 926 } 927 } 928 else 929 { 930 /* PATH@BASE_REVISION exists on the same 931 line of history at RANGE->START and RANGE->END. 932 Now check that PATH@BASE_REVISION's path 933 names at RANGE->START and RANGE->END are the same. 934 If the names are not the same then the mergeinfo 935 describing PATH@RANGE->START through 936 PATH@RANGE->END actually belong to some other 937 line of history and we want to record this 938 mergeinfo, not filter it. */ 939 if (strcmp(start_loc->url, merge_source_url) != 0) 940 { 941 APR_ARRAY_PUSH(adjusted_rangelist, 942 svn_merge_range_t *) = range; 943 } 944 } 945 /* else no need to add, this mergeinfo is 946 all on the same line of history. */ 947 } /* for (j = 0; j < rangelist->nelts; j++) */ 948 949 /* Add any rangelists for source_path that are not 950 self-referential. */ 951 if (adjusted_rangelist->nelts) 952 { 953 if (!filtered_younger_mergeinfo) 954 filtered_younger_mergeinfo = apr_hash_make(iterpool); 955 svn_hash_sets(filtered_younger_mergeinfo, source_path, 956 adjusted_rangelist); 957 } 958 959 } /* Iteration over each merge source in younger_mergeinfo. */ 960 } /* if (younger_mergeinfo) */ 961 962 /* Filter self-referential mergeinfo from "older" mergeinfo. */ 963 if (mergeinfo) 964 { 965 svn_mergeinfo_t implicit_mergeinfo; 966 967 SVN_ERR(svn_client__get_history_as_mergeinfo( 968 &implicit_mergeinfo, NULL, 969 &target_base, target_base.rev, SVN_INVALID_REVNUM, 970 ra_session, ctx, iterpool)); 971 972 /* Remove PATH's implicit mergeinfo from the incoming mergeinfo. */ 973 SVN_ERR(svn_mergeinfo_remove2(&filtered_mergeinfo, 974 implicit_mergeinfo, 975 mergeinfo, TRUE, iterpool, iterpool)); 976 } 977 978 /* Combine whatever older and younger filtered mergeinfo exists 979 into filtered_mergeinfo. */ 980 if (filtered_mergeinfo && filtered_younger_mergeinfo) 981 SVN_ERR(svn_mergeinfo_merge2(filtered_mergeinfo, 982 filtered_younger_mergeinfo, iterpool, 983 iterpool)); 984 else if (filtered_younger_mergeinfo) 985 filtered_mergeinfo = filtered_younger_mergeinfo; 986 987 /* If there is any incoming mergeinfo remaining after filtering 988 then put it in adjusted_props. */ 989 if (filtered_mergeinfo && apr_hash_count(filtered_mergeinfo)) 990 { 991 /* Convert filtered_mergeinfo to a svn_prop_t and put it 992 back in the array. */ 993 svn_string_t *filtered_mergeinfo_str; 994 svn_prop_t *adjusted_prop = apr_pcalloc(pool, 995 sizeof(*adjusted_prop)); 996 SVN_ERR(svn_mergeinfo_to_string(&filtered_mergeinfo_str, 997 filtered_mergeinfo, 998 pool)); 999 adjusted_prop->name = SVN_PROP_MERGEINFO; 1000 adjusted_prop->value = filtered_mergeinfo_str; 1001 APR_ARRAY_PUSH(adjusted_props, svn_prop_t) = *adjusted_prop; 1002 } 1003 } 1004 svn_pool_destroy(iterpool); 1005 1006 *props = adjusted_props; 1007 return SVN_NO_ERROR; 1008} 1009 1010/* Prepare a set of property changes PROPCHANGES to be used for a merge 1011 operation on LOCAL_ABSPATH. 1012 1013 Remove all non-regular prop-changes (entry-props and WC-props). 1014 Remove all non-mergeinfo prop-changes if it's a record-only merge. 1015 Remove self-referential mergeinfo (### in some cases...) 1016 Remove foreign-repository mergeinfo (### in some cases...) 1017 1018 Store the resulting property changes in *PROP_UPDATES. 1019 Store information on where mergeinfo is updated in MERGE_B. 1020 1021 Used for both file and directory property merges. */ 1022static svn_error_t * 1023prepare_merge_props_changed(const apr_array_header_t **prop_updates, 1024 const char *local_abspath, 1025 const apr_array_header_t *propchanges, 1026 merge_cmd_baton_t *merge_b, 1027 apr_pool_t *result_pool, 1028 apr_pool_t *scratch_pool) 1029{ 1030 apr_array_header_t *props; 1031 1032 SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath)); 1033 1034 /* We only want to merge "regular" version properties: by 1035 definition, 'svn merge' shouldn't touch any data within .svn/ */ 1036 SVN_ERR(svn_categorize_props(propchanges, NULL, NULL, &props, 1037 result_pool)); 1038 1039 /* If we are only applying mergeinfo changes then we need to do 1040 additional filtering of PROPS so it contains only mergeinfo changes. */ 1041 if (merge_b->record_only && props->nelts) 1042 { 1043 apr_array_header_t *mergeinfo_props = 1044 apr_array_make(result_pool, 1, sizeof(svn_prop_t)); 1045 int i; 1046 1047 for (i = 0; i < props->nelts; i++) 1048 { 1049 svn_prop_t *prop = &APR_ARRAY_IDX(props, i, svn_prop_t); 1050 1051 if (strcmp(prop->name, SVN_PROP_MERGEINFO) == 0) 1052 { 1053 APR_ARRAY_PUSH(mergeinfo_props, svn_prop_t) = *prop; 1054 break; 1055 } 1056 } 1057 props = mergeinfo_props; 1058 } 1059 1060 if (props->nelts) 1061 { 1062 /* Issue #3383: We don't want mergeinfo from a foreign repos. 1063 1064 If this is a merge from a foreign repository we must strip all 1065 incoming mergeinfo (including mergeinfo deletions). */ 1066 if (! merge_b->same_repos) 1067 SVN_ERR(omit_mergeinfo_changes(&props, props, result_pool)); 1068 1069 /* If this is a forward merge then don't add new mergeinfo to 1070 PATH that is already part of PATH's own history, see 1071 http://svn.haxx.se/dev/archive-2008-09/0006.shtml. If the 1072 merge sources are not ancestral then there is no concept of a 1073 'forward' or 'reverse' merge and we filter unconditionally. */ 1074 if (merge_b->merge_source.loc1->rev < merge_b->merge_source.loc2->rev 1075 || !merge_b->merge_source.ancestral) 1076 { 1077 if (HONOR_MERGEINFO(merge_b) || merge_b->reintegrate_merge) 1078 SVN_ERR(filter_self_referential_mergeinfo(&props, 1079 local_abspath, 1080 merge_b->ra_session2, 1081 merge_b->ctx, 1082 result_pool)); 1083 } 1084 } 1085 *prop_updates = props; 1086 1087 /* Make a record in BATON if we find a PATH where mergeinfo is added 1088 where none existed previously or PATH is having its existing 1089 mergeinfo deleted. */ 1090 if (props->nelts) 1091 { 1092 int i; 1093 1094 for (i = 0; i < props->nelts; ++i) 1095 { 1096 svn_prop_t *prop = &APR_ARRAY_IDX(props, i, svn_prop_t); 1097 1098 if (strcmp(prop->name, SVN_PROP_MERGEINFO) == 0) 1099 { 1100 /* Does LOCAL_ABSPATH have any pristine mergeinfo? */ 1101 svn_boolean_t has_pristine_mergeinfo = FALSE; 1102 apr_hash_t *pristine_props; 1103 1104 SVN_ERR(svn_wc_get_pristine_props(&pristine_props, 1105 merge_b->ctx->wc_ctx, 1106 local_abspath, 1107 scratch_pool, 1108 scratch_pool)); 1109 1110 if (pristine_props 1111 && svn_hash_gets(pristine_props, SVN_PROP_MERGEINFO)) 1112 has_pristine_mergeinfo = TRUE; 1113 1114 if (!has_pristine_mergeinfo && prop->value) 1115 { 1116 alloc_and_store_path(&merge_b->paths_with_new_mergeinfo, 1117 local_abspath, merge_b->pool); 1118 } 1119 else if (has_pristine_mergeinfo && !prop->value) 1120 { 1121 alloc_and_store_path(&merge_b->paths_with_deleted_mergeinfo, 1122 local_abspath, merge_b->pool); 1123 } 1124 } 1125 } 1126 } 1127 1128 return SVN_NO_ERROR; 1129} 1130 1131#define CONFLICT_REASON_NONE ((svn_wc_conflict_reason_t)-1) 1132#define CONFLICT_REASON_SKIP ((svn_wc_conflict_reason_t)-2) 1133#define CONFLICT_REASON_SKIP_WC ((svn_wc_conflict_reason_t)-3) 1134 1135/* Baton used for testing trees for being editted while performing tree 1136 conflict detection for incoming deletes */ 1137struct dir_delete_baton_t 1138{ 1139 /* Reference to dir baton of directory that is the root of the deletion */ 1140 struct merge_dir_baton_t *del_root; 1141 1142 /* Boolean indicating that some edit is found. Allows avoiding more work */ 1143 svn_boolean_t found_edit; 1144 1145 /* A list of paths that are compared. Kept up to date until FOUND_EDIT is 1146 set to TRUE */ 1147 apr_hash_t *compared_abspaths; 1148}; 1149 1150/* Baton for the merge_dir_*() functions. Initialized in merge_dir_opened() */ 1151struct merge_dir_baton_t 1152{ 1153 /* Reference to the parent baton, unless the parent is the anchor, in which 1154 case PARENT_BATON is NULL */ 1155 struct merge_dir_baton_t *parent_baton; 1156 1157 /* The pool containing this baton. Use for RESULT_POOL for storing in this 1158 baton */ 1159 apr_pool_t *pool; 1160 1161 /* This directory doesn't have a representation in the working copy, so any 1162 operation on it will be skipped and possibly cause a tree conflict on the 1163 shadow root */ 1164 svn_boolean_t shadowed; 1165 1166 /* This node or one of its descendants received operational changes from the 1167 merge. If this node is the shadow root its tree conflict status has been 1168 applied */ 1169 svn_boolean_t edited; 1170 1171 /* If a tree conflict will be installed once edited, it's reason. If a skip 1172 should be produced its reason. Otherwise CONFLICT_REASON_NONE for no tree 1173 conflict. 1174 1175 Special values: 1176 CONFLICT_REASON_SKIP: 1177 The node will be skipped with content and property state as stored in 1178 SKIP_REASON. 1179 1180 CONFLICT_REASON_SKIP_WC: 1181 The node will be skipped as an obstructing working copy. 1182 */ 1183 svn_wc_conflict_reason_t tree_conflict_reason; 1184 svn_wc_conflict_action_t tree_conflict_action; 1185 1186 /* When TREE_CONFLICT_REASON is CONFLICT_REASON_SKIP, the skip state to 1187 add to the notification */ 1188 svn_wc_notify_state_t skip_reason; 1189 1190 /* TRUE if the node was added by this merge. Otherwise FALSE */ 1191 svn_boolean_t added; 1192 svn_boolean_t add_is_replace; /* Add is second part of replace */ 1193 1194 /* TRUE if we are taking over an existing directory as addition, otherwise 1195 FALSE. */ 1196 svn_boolean_t add_existing; 1197 1198 /* NULL, or an hashtable mapping const char * local_abspaths to 1199 const char *kind mapping, containing deleted nodes that still need a delete 1200 notification (which may be a replaced notification if the node is not just 1201 deleted) */ 1202 apr_hash_t *pending_deletes; 1203 1204 /* NULL, or an hashtable mapping const char * LOCAL_ABSPATHs to 1205 a const svn_wc_conflict_description2_t * instance, describing the just 1206 installed conflict */ 1207 apr_hash_t *new_tree_conflicts; 1208 1209 /* If not NULL, a reference to the information of the delete test that is 1210 currently in progress. Allocated in the root-directory baton, referenced 1211 from all descendants */ 1212 struct dir_delete_baton_t *delete_state; 1213}; 1214 1215/* Baton for the merge_dir_*() functions. Initialized in merge_file_opened() */ 1216struct merge_file_baton_t 1217{ 1218 /* Reference to the parent baton, unless the parent is the anchor, in which 1219 case PARENT_BATON is NULL */ 1220 struct merge_dir_baton_t *parent_baton; 1221 1222 /* This file doesn't have a representation in the working copy, so any 1223 operation on it will be skipped and possibly cause a tree conflict 1224 on the shadow root */ 1225 svn_boolean_t shadowed; 1226 1227 /* This node received operational changes from the merge. If this node 1228 is the shadow root its tree conflict status has been applied */ 1229 svn_boolean_t edited; 1230 1231 /* If a tree conflict will be installed once edited, it's reason. If a skip 1232 should be produced its reason. Some special values are defined. See the 1233 merge_tree_baton_t for an explanation. */ 1234 svn_wc_conflict_reason_t tree_conflict_reason; 1235 svn_wc_conflict_action_t tree_conflict_action; 1236 1237 /* When TREE_CONFLICT_REASON is CONFLICT_REASON_SKIP, the skip state to 1238 add to the notification */ 1239 svn_wc_notify_state_t skip_reason; 1240 1241 /* TRUE if the node was added by this merge. Otherwise FALSE */ 1242 svn_boolean_t added; 1243 svn_boolean_t add_is_replace; /* Add is second part of replace */ 1244}; 1245 1246/* Forward declaration */ 1247static svn_error_t * 1248notify_merge_begin(merge_cmd_baton_t *merge_b, 1249 const char *local_abspath, 1250 svn_boolean_t delete_action, 1251 apr_pool_t *scratch_pool); 1252 1253/* Record the skip for future processing and (later) produce the 1254 skip notification */ 1255static svn_error_t * 1256record_skip(merge_cmd_baton_t *merge_b, 1257 const char *local_abspath, 1258 svn_node_kind_t kind, 1259 svn_wc_notify_action_t action, 1260 svn_wc_notify_state_t state, 1261 struct merge_dir_baton_t *pdb, 1262 apr_pool_t *scratch_pool) 1263{ 1264 if (merge_b->record_only) 1265 return SVN_NO_ERROR; /* ### Why? - Legacy compatibility */ 1266 1267 if ((merge_b->merge_source.ancestral || merge_b->reintegrate_merge) 1268 && !(pdb && pdb->shadowed)) 1269 { 1270 store_path(merge_b->skipped_abspaths, local_abspath); 1271 } 1272 1273 if (merge_b->ctx->notify_func2) 1274 { 1275 svn_wc_notify_t *notify; 1276 1277 SVN_ERR(notify_merge_begin(merge_b, local_abspath, FALSE, scratch_pool)); 1278 1279 notify = svn_wc_create_notify(local_abspath, action, scratch_pool); 1280 notify->kind = kind; 1281 notify->content_state = notify->prop_state = state; 1282 1283 (*merge_b->ctx->notify_func2)(merge_b->ctx->notify_baton2, notify, 1284 scratch_pool); 1285 } 1286 return SVN_NO_ERROR; 1287} 1288 1289/* Record a tree conflict in the WC, unless this is a dry run or a record- 1290 * only merge, or if a tree conflict is already flagged for the VICTIM_PATH. 1291 * (The latter can happen if a merge-tracking-aware merge is doing multiple 1292 * editor drives because of a gap in the range of eligible revisions.) 1293 * 1294 * The tree conflict, with its victim specified by VICTIM_PATH, is 1295 * assumed to have happened during a merge using merge baton MERGE_B. 1296 * 1297 * NODE_KIND must be the node kind of "old" and "theirs" and "mine"; 1298 * this function cannot cope with node kind clashes. 1299 * ACTION and REASON correspond to the fields 1300 * of the same names in svn_wc_tree_conflict_description_t. 1301 */ 1302static svn_error_t * 1303record_tree_conflict(merge_cmd_baton_t *merge_b, 1304 const char *local_abspath, 1305 struct merge_dir_baton_t *parent_baton, 1306 svn_node_kind_t node_kind, 1307 svn_wc_conflict_action_t action, 1308 svn_wc_conflict_reason_t reason, 1309 const svn_wc_conflict_description2_t *existing_conflict, 1310 svn_boolean_t notify_tc, 1311 apr_pool_t *scratch_pool) 1312{ 1313 svn_wc_context_t *wc_ctx = merge_b->ctx->wc_ctx; 1314 1315 if (merge_b->record_only) 1316 return SVN_NO_ERROR; 1317 1318 if (merge_b->merge_source.ancestral 1319 || merge_b->reintegrate_merge) 1320 { 1321 store_path(merge_b->tree_conflicted_abspaths, local_abspath); 1322 } 1323 1324 alloc_and_store_path(&merge_b->conflicted_paths, local_abspath, 1325 merge_b->pool); 1326 1327 if (!merge_b->dry_run) 1328 { 1329 svn_wc_conflict_description2_t *conflict; 1330 const svn_wc_conflict_version_t *left; 1331 const svn_wc_conflict_version_t *right; 1332 apr_pool_t *result_pool = parent_baton ? parent_baton->pool 1333 : scratch_pool; 1334 1335 if (reason == svn_wc_conflict_reason_deleted) 1336 { 1337 const char *moved_to_abspath; 1338 1339 SVN_ERR(svn_wc__node_was_moved_away(&moved_to_abspath, NULL, 1340 wc_ctx, local_abspath, 1341 scratch_pool, scratch_pool)); 1342 1343 if (moved_to_abspath) 1344 { 1345 /* Local abspath itself has been moved away. If only a 1346 descendant is moved away, we call the node itself deleted */ 1347 reason = svn_wc_conflict_reason_moved_away; 1348 } 1349 } 1350 else if (reason == svn_wc_conflict_reason_added) 1351 { 1352 const char *moved_from_abspath; 1353 SVN_ERR(svn_wc__node_was_moved_here(&moved_from_abspath, NULL, 1354 wc_ctx, local_abspath, 1355 scratch_pool, scratch_pool)); 1356 if (moved_from_abspath) 1357 reason = svn_wc_conflict_reason_moved_here; 1358 } 1359 1360 SVN_ERR(make_conflict_versions(&left, &right, local_abspath, node_kind, 1361 &merge_b->merge_source, merge_b->target, 1362 result_pool, scratch_pool)); 1363 1364 /* Fix up delete of file, add of dir replacement (or other way around) */ 1365 if (existing_conflict != NULL && existing_conflict->src_left_version) 1366 left = existing_conflict->src_left_version; 1367 1368 conflict = svn_wc_conflict_description_create_tree2( 1369 local_abspath, node_kind, svn_wc_operation_merge, 1370 left, right, result_pool); 1371 1372 conflict->action = action; 1373 conflict->reason = reason; 1374 1375 /* May return SVN_ERR_WC_PATH_UNEXPECTED_STATUS */ 1376 if (existing_conflict) 1377 SVN_ERR(svn_wc__del_tree_conflict(wc_ctx, local_abspath, 1378 scratch_pool)); 1379 1380 SVN_ERR(svn_wc__add_tree_conflict(merge_b->ctx->wc_ctx, conflict, 1381 scratch_pool)); 1382 1383 if (parent_baton) 1384 { 1385 if (! parent_baton->new_tree_conflicts) 1386 parent_baton->new_tree_conflicts = apr_hash_make(result_pool); 1387 1388 svn_hash_sets(parent_baton->new_tree_conflicts, 1389 apr_pstrdup(result_pool, local_abspath), 1390 conflict); 1391 } 1392 1393 /* ### TODO: Store in parent baton */ 1394 } 1395 1396 /* On a replacement we currently get two tree conflicts */ 1397 if (merge_b->ctx->notify_func2 && notify_tc) 1398 { 1399 svn_wc_notify_t *notify; 1400 1401 SVN_ERR(notify_merge_begin(merge_b, local_abspath, FALSE, scratch_pool)); 1402 1403 notify = svn_wc_create_notify(local_abspath, svn_wc_notify_tree_conflict, 1404 scratch_pool); 1405 notify->kind = node_kind; 1406 1407 (*merge_b->ctx->notify_func2)(merge_b->ctx->notify_baton2, notify, 1408 scratch_pool); 1409 } 1410 1411 return SVN_NO_ERROR; 1412} 1413 1414/* Record the add for future processing and produce the 1415 update_add notification 1416 */ 1417static svn_error_t * 1418record_update_add(merge_cmd_baton_t *merge_b, 1419 const char *local_abspath, 1420 svn_node_kind_t kind, 1421 svn_boolean_t notify_replaced, 1422 apr_pool_t *scratch_pool) 1423{ 1424 if (merge_b->merge_source.ancestral || merge_b->reintegrate_merge) 1425 { 1426 store_path(merge_b->merged_abspaths, local_abspath); 1427 } 1428 1429 if (merge_b->ctx->notify_func2) 1430 { 1431 svn_wc_notify_t *notify; 1432 svn_wc_notify_action_t action = svn_wc_notify_update_add; 1433 1434 SVN_ERR(notify_merge_begin(merge_b, local_abspath, FALSE, scratch_pool)); 1435 1436 if (notify_replaced) 1437 action = svn_wc_notify_update_replace; 1438 1439 notify = svn_wc_create_notify(local_abspath, action, scratch_pool); 1440 notify->kind = kind; 1441 1442 (*merge_b->ctx->notify_func2)(merge_b->ctx->notify_baton2, notify, 1443 scratch_pool); 1444 } 1445 1446 return SVN_NO_ERROR; 1447} 1448 1449/* Record the update for future processing and produce the 1450 update_update notification */ 1451static svn_error_t * 1452record_update_update(merge_cmd_baton_t *merge_b, 1453 const char *local_abspath, 1454 svn_node_kind_t kind, 1455 svn_wc_notify_state_t content_state, 1456 svn_wc_notify_state_t prop_state, 1457 apr_pool_t *scratch_pool) 1458{ 1459 if (merge_b->merge_source.ancestral || merge_b->reintegrate_merge) 1460 { 1461 store_path(merge_b->merged_abspaths, local_abspath); 1462 } 1463 1464 if (merge_b->ctx->notify_func2) 1465 { 1466 svn_wc_notify_t *notify; 1467 1468 SVN_ERR(notify_merge_begin(merge_b, local_abspath, FALSE, scratch_pool)); 1469 1470 notify = svn_wc_create_notify(local_abspath, svn_wc_notify_update_update, 1471 scratch_pool); 1472 notify->kind = kind; 1473 notify->content_state = content_state; 1474 notify->prop_state = prop_state; 1475 1476 (*merge_b->ctx->notify_func2)(merge_b->ctx->notify_baton2, notify, 1477 scratch_pool); 1478 } 1479 1480 return SVN_NO_ERROR; 1481} 1482 1483/* Record the delete for future processing and for (later) producing the 1484 update_delete notification */ 1485static svn_error_t * 1486record_update_delete(merge_cmd_baton_t *merge_b, 1487 struct merge_dir_baton_t *parent_db, 1488 const char *local_abspath, 1489 svn_node_kind_t kind, 1490 apr_pool_t *scratch_pool) 1491{ 1492 /* Update the lists of merged, skipped, tree-conflicted and added paths. */ 1493 if (merge_b->merge_source.ancestral 1494 || merge_b->reintegrate_merge) 1495 { 1496 /* Issue #4166: If a previous merge added NOTIFY_ABSPATH, but we 1497 are now deleting it, then remove it from the list of added 1498 paths. */ 1499 svn_hash_sets(merge_b->added_abspaths, local_abspath, NULL); 1500 store_path(merge_b->merged_abspaths, local_abspath); 1501 } 1502 1503 SVN_ERR(notify_merge_begin(merge_b, local_abspath, TRUE, scratch_pool)); 1504 1505 if (parent_db) 1506 { 1507 const char *dup_abspath = apr_pstrdup(parent_db->pool, local_abspath); 1508 1509 if (!parent_db->pending_deletes) 1510 parent_db->pending_deletes = apr_hash_make(parent_db->pool); 1511 1512 svn_hash_sets(parent_db->pending_deletes, dup_abspath, 1513 svn_node_kind_to_word(kind)); 1514 } 1515 1516 return SVN_NO_ERROR; 1517} 1518 1519/* Notify the pending 'D'eletes, that were waiting to see if a matching 'A'dd 1520 might make them a 'R'eplace. */ 1521static svn_error_t * 1522handle_pending_notifications(merge_cmd_baton_t *merge_b, 1523 struct merge_dir_baton_t *db, 1524 apr_pool_t *scratch_pool) 1525{ 1526 if (merge_b->ctx->notify_func2 && db->pending_deletes) 1527 { 1528 apr_hash_index_t *hi; 1529 1530 for (hi = apr_hash_first(scratch_pool, db->pending_deletes); 1531 hi; 1532 hi = apr_hash_next(hi)) 1533 { 1534 const char *del_abspath = svn__apr_hash_index_key(hi); 1535 svn_wc_notify_t *notify; 1536 1537 notify = svn_wc_create_notify(del_abspath, 1538 svn_wc_notify_update_delete, 1539 scratch_pool); 1540 notify->kind = svn_node_kind_from_word( 1541 svn__apr_hash_index_val(hi)); 1542 1543 (*merge_b->ctx->notify_func2)(merge_b->ctx->notify_baton2, 1544 notify, scratch_pool); 1545 } 1546 1547 db->pending_deletes = NULL; 1548 } 1549 return SVN_NO_ERROR; 1550} 1551 1552/* Helper function for the merge_dir_*() and merge_file_*() functions. 1553 1554 Installs and notifies pre-recorded tree conflicts and skips for 1555 ancestors of operational merges 1556 */ 1557static svn_error_t * 1558mark_dir_edited(merge_cmd_baton_t *merge_b, 1559 struct merge_dir_baton_t *db, 1560 const char *local_abspath, 1561 apr_pool_t *scratch_pool) 1562{ 1563 /* ### Too much common code with mark_file_edited */ 1564 if (db->edited) 1565 return SVN_NO_ERROR; 1566 1567 if (db->parent_baton && !db->parent_baton->edited) 1568 { 1569 const char *dir_abspath = svn_dirent_dirname(local_abspath, 1570 scratch_pool); 1571 1572 SVN_ERR(mark_dir_edited(merge_b, db->parent_baton, dir_abspath, 1573 scratch_pool)); 1574 } 1575 1576 db->edited = TRUE; 1577 1578 if (! db->shadowed) 1579 return SVN_NO_ERROR; /* Easy out */ 1580 1581 if (db->parent_baton 1582 && db->parent_baton->delete_state 1583 && db->tree_conflict_reason != CONFLICT_REASON_NONE) 1584 { 1585 db->parent_baton->delete_state->found_edit = TRUE; 1586 } 1587 else if (db->tree_conflict_reason == CONFLICT_REASON_SKIP 1588 || db->tree_conflict_reason == CONFLICT_REASON_SKIP_WC) 1589 { 1590 /* open_directory() decided not to flag a tree conflict, but 1591 for clarity we produce a skip for this node that 1592 most likely isn't touched by the merge itself */ 1593 1594 if (merge_b->ctx->notify_func2) 1595 { 1596 svn_wc_notify_t *notify; 1597 1598 SVN_ERR(notify_merge_begin(merge_b, local_abspath, FALSE, 1599 scratch_pool)); 1600 1601 notify = svn_wc_create_notify( 1602 local_abspath, 1603 (db->tree_conflict_reason == CONFLICT_REASON_SKIP) 1604 ? svn_wc_notify_skip 1605 : svn_wc_notify_update_skip_obstruction, 1606 scratch_pool); 1607 notify->kind = svn_node_dir; 1608 notify->content_state = notify->prop_state = db->skip_reason; 1609 1610 (*merge_b->ctx->notify_func2)(merge_b->ctx->notify_baton2, 1611 notify, 1612 scratch_pool); 1613 } 1614 1615 if (merge_b->merge_source.ancestral 1616 || merge_b->reintegrate_merge) 1617 { 1618 store_path(merge_b->skipped_abspaths, local_abspath); 1619 } 1620 } 1621 else if (db->tree_conflict_reason != CONFLICT_REASON_NONE) 1622 { 1623 /* open_directory() decided that a tree conflict should be raised */ 1624 1625 SVN_ERR(record_tree_conflict(merge_b, local_abspath, db->parent_baton, 1626 svn_node_dir, db->tree_conflict_action, 1627 db->tree_conflict_reason, 1628 NULL, TRUE, 1629 scratch_pool)); 1630 } 1631 1632 return SVN_NO_ERROR; 1633} 1634 1635/* Helper function for the merge_file_*() functions. 1636 1637 Installs and notifies pre-recorded tree conflicts and skips for 1638 ancestors of operational merges 1639 */ 1640static svn_error_t * 1641mark_file_edited(merge_cmd_baton_t *merge_b, 1642 struct merge_file_baton_t *fb, 1643 const char *local_abspath, 1644 apr_pool_t *scratch_pool) 1645{ 1646 /* ### Too much common code with mark_dir_edited */ 1647 if (fb->edited) 1648 return SVN_NO_ERROR; 1649 1650 if (fb->parent_baton && !fb->parent_baton->edited) 1651 { 1652 const char *dir_abspath = svn_dirent_dirname(local_abspath, 1653 scratch_pool); 1654 1655 SVN_ERR(mark_dir_edited(merge_b, fb->parent_baton, dir_abspath, 1656 scratch_pool)); 1657 } 1658 1659 fb->edited = TRUE; 1660 1661 if (! fb->shadowed) 1662 return SVN_NO_ERROR; /* Easy out */ 1663 1664 if (fb->parent_baton 1665 && fb->parent_baton->delete_state 1666 && fb->tree_conflict_reason != CONFLICT_REASON_NONE) 1667 { 1668 fb->parent_baton->delete_state->found_edit = TRUE; 1669 } 1670 else if (fb->tree_conflict_reason == CONFLICT_REASON_SKIP 1671 || fb->tree_conflict_reason == CONFLICT_REASON_SKIP_WC) 1672 { 1673 /* open_directory() decided not to flag a tree conflict, but 1674 for clarity we produce a skip for this node that 1675 most likely isn't touched by the merge itself */ 1676 1677 if (merge_b->ctx->notify_func2) 1678 { 1679 svn_wc_notify_t *notify; 1680 1681 SVN_ERR(notify_merge_begin(merge_b, local_abspath, FALSE, 1682 scratch_pool)); 1683 1684 notify = svn_wc_create_notify(local_abspath, svn_wc_notify_skip, 1685 scratch_pool); 1686 notify->kind = svn_node_file; 1687 notify->content_state = notify->prop_state = fb->skip_reason; 1688 1689 (*merge_b->ctx->notify_func2)(merge_b->ctx->notify_baton2, 1690 notify, 1691 scratch_pool); 1692 } 1693 1694 if (merge_b->merge_source.ancestral 1695 || merge_b->reintegrate_merge) 1696 { 1697 store_path(merge_b->skipped_abspaths, local_abspath); 1698 } 1699 } 1700 else if (fb->tree_conflict_reason != CONFLICT_REASON_NONE) 1701 { 1702 /* open_file() decided that a tree conflict should be raised */ 1703 1704 SVN_ERR(record_tree_conflict(merge_b, local_abspath, fb->parent_baton, 1705 svn_node_file, fb->tree_conflict_action, 1706 fb->tree_conflict_reason, 1707 NULL, TRUE, 1708 scratch_pool)); 1709 } 1710 1711 return SVN_NO_ERROR; 1712} 1713 1714/* An svn_diff_tree_processor_t function. 1715 1716 Called before either merge_file_changed(), merge_file_added(), 1717 merge_file_deleted() or merge_file_closed(), unless it sets *SKIP to TRUE. 1718 1719 When *SKIP is TRUE, the diff driver avoids work on getting the details 1720 for the closing callbacks. 1721 */ 1722static svn_error_t * 1723merge_file_opened(void **new_file_baton, 1724 svn_boolean_t *skip, 1725 const char *relpath, 1726 const svn_diff_source_t *left_source, 1727 const svn_diff_source_t *right_source, 1728 const svn_diff_source_t *copyfrom_source, 1729 void *dir_baton, 1730 const struct svn_diff_tree_processor_t *processor, 1731 apr_pool_t *result_pool, 1732 apr_pool_t *scratch_pool) 1733{ 1734 merge_cmd_baton_t *merge_b = processor->baton; 1735 struct merge_dir_baton_t *pdb = dir_baton; 1736 struct merge_file_baton_t *fb; 1737 const char *local_abspath = svn_dirent_join(merge_b->target->abspath, 1738 relpath, scratch_pool); 1739 1740 fb = apr_pcalloc(result_pool, sizeof(*fb)); 1741 fb->tree_conflict_reason = CONFLICT_REASON_NONE; 1742 fb->tree_conflict_action = svn_wc_conflict_action_edit; 1743 fb->skip_reason = svn_wc_notify_state_unknown; 1744 1745 *new_file_baton = fb; 1746 1747 if (pdb) 1748 { 1749 fb->parent_baton = pdb; 1750 fb->shadowed = pdb->shadowed; 1751 fb->skip_reason = pdb->skip_reason; 1752 } 1753 1754 if (fb->shadowed) 1755 { 1756 /* An ancestor is tree conflicted. Nothing to do here. */ 1757 } 1758 else if (left_source != NULL) 1759 { 1760 /* Node is expected to be a file, which will be changed or deleted. */ 1761 svn_node_kind_t kind; 1762 svn_boolean_t is_deleted; 1763 svn_boolean_t excluded; 1764 svn_depth_t parent_depth; 1765 1766 if (! right_source) 1767 fb->tree_conflict_action = svn_wc_conflict_action_delete; 1768 1769 { 1770 svn_wc_notify_state_t obstr_state; 1771 1772 SVN_ERR(perform_obstruction_check(&obstr_state, &is_deleted, &excluded, 1773 &kind, &parent_depth, 1774 merge_b, local_abspath, 1775 scratch_pool)); 1776 1777 if (obstr_state != svn_wc_notify_state_inapplicable) 1778 { 1779 fb->shadowed = TRUE; 1780 fb->tree_conflict_reason = CONFLICT_REASON_SKIP; 1781 fb->skip_reason = obstr_state; 1782 return SVN_NO_ERROR; 1783 } 1784 1785 if (is_deleted) 1786 kind = svn_node_none; 1787 } 1788 1789 if (kind == svn_node_none) 1790 { 1791 fb->shadowed = TRUE; 1792 1793 /* If this is not the merge target and the parent is too shallow to 1794 contain this directory, and the directory is not present 1795 via exclusion or depth filtering, skip it instead of recording 1796 a tree conflict. 1797 1798 Non-inheritable mergeinfo will be recorded, allowing 1799 future merges into non-shallow working copies to merge 1800 changes we missed this time around. */ 1801 if (pdb && (excluded 1802 || (parent_depth != svn_depth_unknown && 1803 parent_depth < svn_depth_files))) 1804 { 1805 fb->shadowed = TRUE; 1806 1807 fb->tree_conflict_reason = CONFLICT_REASON_SKIP; 1808 fb->skip_reason = svn_wc_notify_state_missing; 1809 return SVN_NO_ERROR; 1810 } 1811 1812 if (is_deleted) 1813 fb->tree_conflict_reason = svn_wc_conflict_reason_deleted; 1814 else 1815 fb->tree_conflict_reason = svn_wc_conflict_reason_missing; 1816 1817 /* ### Similar to directory */ 1818 *skip = TRUE; 1819 SVN_ERR(mark_file_edited(merge_b, fb, local_abspath, scratch_pool)); 1820 return SVN_NO_ERROR; 1821 /* ### /Similar */ 1822 } 1823 else if (kind != svn_node_file) 1824 { 1825 fb->shadowed = TRUE; 1826 1827 fb->tree_conflict_reason = svn_wc_conflict_reason_obstructed; 1828 1829 /* ### Similar to directory */ 1830 *skip = TRUE; 1831 SVN_ERR(mark_file_edited(merge_b, fb, local_abspath, scratch_pool)); 1832 return SVN_NO_ERROR; 1833 /* ### /Similar */ 1834 } 1835 1836 if (! right_source) 1837 { 1838 /* We want to delete the directory */ 1839 fb->tree_conflict_action = svn_wc_conflict_action_delete; 1840 SVN_ERR(mark_file_edited(merge_b, fb, local_abspath, scratch_pool)); 1841 1842 if (fb->shadowed) 1843 { 1844 return SVN_NO_ERROR; /* Already set a tree conflict */ 1845 } 1846 1847 /* Comparison mode to verify for delete tree conflicts? */ 1848 if (pdb && pdb->delete_state 1849 && pdb->delete_state->found_edit) 1850 { 1851 /* Earlier nodes found a conflict. Done. */ 1852 *skip = TRUE; 1853 } 1854 } 1855 } 1856 else 1857 { 1858 const svn_wc_conflict_description2_t *old_tc = NULL; 1859 1860 /* The node doesn't exist pre-merge: We have an addition */ 1861 fb->added = TRUE; 1862 fb->tree_conflict_action = svn_wc_conflict_action_add; 1863 1864 if (pdb && pdb->pending_deletes 1865 && svn_hash_gets(pdb->pending_deletes, local_abspath)) 1866 { 1867 fb->add_is_replace = TRUE; 1868 fb->tree_conflict_action = svn_wc_conflict_action_replace; 1869 1870 svn_hash_sets(pdb->pending_deletes, local_abspath, NULL); 1871 } 1872 1873 if (pdb 1874 && pdb->new_tree_conflicts 1875 && (old_tc = svn_hash_gets(pdb->new_tree_conflicts, local_abspath))) 1876 { 1877 fb->tree_conflict_action = svn_wc_conflict_action_replace; 1878 fb->tree_conflict_reason = old_tc->reason; 1879 1880 /* Update the tree conflict to store that this is a replace */ 1881 SVN_ERR(record_tree_conflict(merge_b, local_abspath, pdb, 1882 svn_node_file, 1883 fb->tree_conflict_action, 1884 fb->tree_conflict_reason, 1885 old_tc, FALSE, 1886 scratch_pool)); 1887 1888 if (old_tc->reason == svn_wc_conflict_reason_deleted 1889 || old_tc->reason == svn_wc_conflict_reason_moved_away) 1890 { 1891 /* Issue #3806: Incoming replacements on local deletes produce 1892 inconsistent result. 1893 1894 In this specific case we can continue applying the add part 1895 of the replacement. */ 1896 } 1897 else 1898 { 1899 *skip = TRUE; 1900 1901 return SVN_NO_ERROR; 1902 } 1903 } 1904 else if (! (merge_b->dry_run 1905 && ((pdb && pdb->added) || fb->add_is_replace))) 1906 { 1907 svn_wc_notify_state_t obstr_state; 1908 svn_node_kind_t kind; 1909 svn_boolean_t is_deleted; 1910 1911 SVN_ERR(perform_obstruction_check(&obstr_state, &is_deleted, NULL, 1912 &kind, NULL, 1913 merge_b, local_abspath, 1914 scratch_pool)); 1915 1916 if (obstr_state != svn_wc_notify_state_inapplicable) 1917 { 1918 /* Skip the obstruction */ 1919 fb->shadowed = TRUE; 1920 fb->tree_conflict_reason = CONFLICT_REASON_SKIP; 1921 fb->skip_reason = obstr_state; 1922 } 1923 else if (kind != svn_node_none && !is_deleted) 1924 { 1925 /* Set a tree conflict */ 1926 fb->shadowed = TRUE; 1927 fb->tree_conflict_reason = svn_wc_conflict_reason_obstructed; 1928 } 1929 } 1930 1931 /* Handle pending conflicts */ 1932 SVN_ERR(mark_file_edited(merge_b, fb, local_abspath, scratch_pool)); 1933 } 1934 1935 return SVN_NO_ERROR; 1936} 1937 1938/* An svn_diff_tree_processor_t function. 1939 * 1940 * Called after merge_file_opened() when a node receives only text and/or 1941 * property changes between LEFT_SOURCE and RIGHT_SOURCE. 1942 * 1943 * left_file and right_file can be NULL when the file is not modified. 1944 * left_props and right_props are always available. 1945 */ 1946static svn_error_t * 1947merge_file_changed(const char *relpath, 1948 const svn_diff_source_t *left_source, 1949 const svn_diff_source_t *right_source, 1950 const char *left_file, 1951 const char *right_file, 1952 /*const*/ apr_hash_t *left_props, 1953 /*const*/ apr_hash_t *right_props, 1954 svn_boolean_t file_modified, 1955 const apr_array_header_t *prop_changes, 1956 void *file_baton, 1957 const struct svn_diff_tree_processor_t *processor, 1958 apr_pool_t *scratch_pool) 1959{ 1960 merge_cmd_baton_t *merge_b = processor->baton; 1961 struct merge_file_baton_t *fb = file_baton; 1962 svn_client_ctx_t *ctx = merge_b->ctx; 1963 const char *local_abspath = svn_dirent_join(merge_b->target->abspath, 1964 relpath, scratch_pool); 1965 const svn_wc_conflict_version_t *left; 1966 const svn_wc_conflict_version_t *right; 1967 svn_wc_notify_state_t text_state; 1968 svn_wc_notify_state_t property_state; 1969 1970 SVN_ERR_ASSERT(local_abspath && svn_dirent_is_absolute(local_abspath)); 1971 SVN_ERR_ASSERT(!left_file || svn_dirent_is_absolute(left_file)); 1972 SVN_ERR_ASSERT(!right_file || svn_dirent_is_absolute(right_file)); 1973 1974 SVN_ERR(mark_file_edited(merge_b, fb, local_abspath, scratch_pool)); 1975 1976 if (fb->shadowed) 1977 { 1978 if (fb->tree_conflict_reason == CONFLICT_REASON_NONE) 1979 { 1980 /* We haven't notified for this node yet: report a skip */ 1981 SVN_ERR(record_skip(merge_b, local_abspath, svn_node_file, 1982 svn_wc_notify_update_shadowed_update, 1983 fb->skip_reason, fb->parent_baton, 1984 scratch_pool)); 1985 } 1986 1987 return SVN_NO_ERROR; 1988 } 1989 1990 /* This callback is essentially no more than a wrapper around 1991 svn_wc_merge5(). Thank goodness that all the 1992 diff-editor-mechanisms are doing the hard work of getting the 1993 fulltexts! */ 1994 1995 property_state = svn_wc_notify_state_unchanged; 1996 text_state = svn_wc_notify_state_unchanged; 1997 1998 SVN_ERR(prepare_merge_props_changed(&prop_changes, local_abspath, 1999 prop_changes, merge_b, 2000 scratch_pool, scratch_pool)); 2001 2002 SVN_ERR(make_conflict_versions(&left, &right, local_abspath, 2003 svn_node_file, &merge_b->merge_source, merge_b->target, 2004 scratch_pool, scratch_pool)); 2005 2006 /* Do property merge now, if we are not going to perform a text merge */ 2007 if ((merge_b->record_only || !left_file) && prop_changes->nelts) 2008 { 2009 SVN_ERR(svn_wc_merge_props3(&property_state, ctx->wc_ctx, local_abspath, 2010 left, right, 2011 left_props, prop_changes, 2012 merge_b->dry_run, 2013 NULL, NULL, 2014 ctx->cancel_func, ctx->cancel_baton, 2015 scratch_pool)); 2016 if (property_state == svn_wc_notify_state_conflicted) 2017 { 2018 alloc_and_store_path(&merge_b->conflicted_paths, local_abspath, 2019 merge_b->pool); 2020 } 2021 } 2022 2023 /* Easy out: We are only applying mergeinfo differences. */ 2024 if (merge_b->record_only) 2025 { 2026 /* NO-OP */ 2027 } 2028 else if (left_file) 2029 { 2030 svn_boolean_t has_local_mods; 2031 enum svn_wc_merge_outcome_t content_outcome; 2032 const char *target_label; 2033 const char *left_label; 2034 const char *right_label; 2035 const char *path_ext = ""; 2036 2037 if (merge_b->ext_patterns && merge_b->ext_patterns->nelts) 2038 { 2039 svn_path_splitext(NULL, &path_ext, local_abspath, scratch_pool); 2040 if (! (*path_ext 2041 && svn_cstring_match_glob_list(path_ext, 2042 merge_b->ext_patterns))) 2043 { 2044 path_ext = ""; 2045 } 2046 } 2047 2048 /* xgettext: the '.working', '.merge-left.r%ld' and 2049 '.merge-right.r%ld' strings are used to tag onto a file 2050 name in case of a merge conflict */ 2051 2052 target_label = apr_psprintf(scratch_pool, _(".working%s%s"), 2053 *path_ext ? "." : "", path_ext); 2054 left_label = apr_psprintf(scratch_pool, 2055 _(".merge-left.r%ld%s%s"), 2056 left_source->revision, 2057 *path_ext ? "." : "", path_ext); 2058 right_label = apr_psprintf(scratch_pool, 2059 _(".merge-right.r%ld%s%s"), 2060 right_source->revision, 2061 *path_ext ? "." : "", path_ext); 2062 2063 SVN_ERR(svn_wc_text_modified_p2(&has_local_mods, ctx->wc_ctx, 2064 local_abspath, FALSE, scratch_pool)); 2065 2066 /* Do property merge and text merge in one step so that keyword expansion 2067 takes into account the new property values. */ 2068 SVN_ERR(svn_wc_merge5(&content_outcome, &property_state, ctx->wc_ctx, 2069 left_file, right_file, local_abspath, 2070 left_label, right_label, target_label, 2071 left, right, 2072 merge_b->dry_run, merge_b->diff3_cmd, 2073 merge_b->merge_options, 2074 left_props, prop_changes, 2075 NULL, NULL, 2076 ctx->cancel_func, 2077 ctx->cancel_baton, 2078 scratch_pool)); 2079 2080 if (content_outcome == svn_wc_merge_conflict 2081 || property_state == svn_wc_notify_state_conflicted) 2082 { 2083 alloc_and_store_path(&merge_b->conflicted_paths, local_abspath, 2084 merge_b->pool); 2085 } 2086 2087 if (content_outcome == svn_wc_merge_conflict) 2088 text_state = svn_wc_notify_state_conflicted; 2089 else if (has_local_mods 2090 && content_outcome != svn_wc_merge_unchanged) 2091 text_state = svn_wc_notify_state_merged; 2092 else if (content_outcome == svn_wc_merge_merged) 2093 text_state = svn_wc_notify_state_changed; 2094 else if (content_outcome == svn_wc_merge_no_merge) 2095 text_state = svn_wc_notify_state_missing; 2096 else /* merge_outcome == svn_wc_merge_unchanged */ 2097 text_state = svn_wc_notify_state_unchanged; 2098 } 2099 2100 if (text_state == svn_wc_notify_state_conflicted 2101 || text_state == svn_wc_notify_state_merged 2102 || text_state == svn_wc_notify_state_changed 2103 || property_state == svn_wc_notify_state_conflicted 2104 || property_state == svn_wc_notify_state_merged 2105 || property_state == svn_wc_notify_state_changed) 2106 { 2107 SVN_ERR(record_update_update(merge_b, local_abspath, svn_node_file, 2108 text_state, property_state, 2109 scratch_pool)); 2110 } 2111 2112 return SVN_NO_ERROR; 2113} 2114 2115/* An svn_diff_tree_processor_t function. 2116 * 2117 * Called after merge_file_opened() when a node doesn't exist in LEFT_SOURCE, 2118 * but does in RIGHT_SOURCE. 2119 * 2120 * When a node is replaced instead of just added a separate opened+deleted will 2121 * be invoked before the current open+added. 2122 */ 2123static svn_error_t * 2124merge_file_added(const char *relpath, 2125 const svn_diff_source_t *copyfrom_source, 2126 const svn_diff_source_t *right_source, 2127 const char *copyfrom_file, 2128 const char *right_file, 2129 /*const*/ apr_hash_t *copyfrom_props, 2130 /*const*/ apr_hash_t *right_props, 2131 void *file_baton, 2132 const struct svn_diff_tree_processor_t *processor, 2133 apr_pool_t *scratch_pool) 2134{ 2135 merge_cmd_baton_t *merge_b = processor->baton; 2136 struct merge_file_baton_t *fb = file_baton; 2137 const char *local_abspath = svn_dirent_join(merge_b->target->abspath, 2138 relpath, scratch_pool); 2139 apr_hash_t *pristine_props; 2140 apr_hash_t *new_props; 2141 2142 SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath)); 2143 2144 SVN_ERR(mark_file_edited(merge_b, fb, local_abspath, scratch_pool)); 2145 2146 if (fb->shadowed) 2147 { 2148 if (fb->tree_conflict_reason == CONFLICT_REASON_NONE) 2149 { 2150 /* We haven't notified for this node yet: report a skip */ 2151 SVN_ERR(record_skip(merge_b, local_abspath, svn_node_file, 2152 svn_wc_notify_update_shadowed_add, 2153 fb->skip_reason, fb->parent_baton, 2154 scratch_pool)); 2155 } 2156 2157 return SVN_NO_ERROR; 2158 } 2159 2160 /* Easy out: We are only applying mergeinfo differences. */ 2161 if (merge_b->record_only) 2162 { 2163 return SVN_NO_ERROR; 2164 } 2165 2166 if ((merge_b->merge_source.ancestral || merge_b->reintegrate_merge) 2167 && ( !fb->parent_baton || !fb->parent_baton->added)) 2168 { 2169 /* Store the roots of added subtrees */ 2170 store_path(merge_b->added_abspaths, local_abspath); 2171 } 2172 2173 if (!merge_b->dry_run) 2174 { 2175 const char *copyfrom_url; 2176 svn_revnum_t copyfrom_rev; 2177 svn_stream_t *new_contents, *pristine_contents; 2178 2179 /* If this is a merge from the same repository as our 2180 working copy, we handle adds as add-with-history. 2181 Otherwise, we'll use a pure add. */ 2182 if (merge_b->same_repos) 2183 { 2184 const char *child = 2185 svn_dirent_skip_ancestor(merge_b->target->abspath, 2186 local_abspath); 2187 SVN_ERR_ASSERT(child != NULL); 2188 copyfrom_url = svn_path_url_add_component2( 2189 merge_b->merge_source.loc2->url, 2190 child, scratch_pool); 2191 copyfrom_rev = right_source->revision; 2192 SVN_ERR(check_repos_match(merge_b->target, local_abspath, 2193 copyfrom_url, scratch_pool)); 2194 SVN_ERR(svn_stream_open_readonly(&pristine_contents, 2195 right_file, 2196 scratch_pool, 2197 scratch_pool)); 2198 new_contents = NULL; /* inherit from new_base_contents */ 2199 2200 pristine_props = right_props; /* Includes last_* information */ 2201 new_props = NULL; /* No local changes */ 2202 2203 if (svn_hash_gets(pristine_props, SVN_PROP_MERGEINFO)) 2204 { 2205 alloc_and_store_path(&merge_b->paths_with_new_mergeinfo, 2206 local_abspath, merge_b->pool); 2207 } 2208 } 2209 else 2210 { 2211 apr_array_header_t *regular_props; 2212 2213 copyfrom_url = NULL; 2214 copyfrom_rev = SVN_INVALID_REVNUM; 2215 2216 pristine_contents = svn_stream_empty(scratch_pool); 2217 SVN_ERR(svn_stream_open_readonly(&new_contents, right_file, 2218 scratch_pool, scratch_pool)); 2219 2220 pristine_props = apr_hash_make(scratch_pool); /* Local addition */ 2221 2222 /* We don't want any foreign properties */ 2223 SVN_ERR(svn_categorize_props(svn_prop_hash_to_array(right_props, 2224 scratch_pool), 2225 NULL, NULL, ®ular_props, 2226 scratch_pool)); 2227 2228 new_props = svn_prop_array_to_hash(regular_props, scratch_pool); 2229 2230 /* Issue #3383: We don't want mergeinfo from a foreign repository. */ 2231 svn_hash_sets(new_props, SVN_PROP_MERGEINFO, NULL); 2232 } 2233 2234 /* Do everything like if we had called 'svn cp PATH1 PATH2'. */ 2235 SVN_ERR(svn_wc_add_repos_file4(merge_b->ctx->wc_ctx, 2236 local_abspath, 2237 pristine_contents, 2238 new_contents, 2239 pristine_props, new_props, 2240 copyfrom_url, copyfrom_rev, 2241 merge_b->ctx->cancel_func, 2242 merge_b->ctx->cancel_baton, 2243 scratch_pool)); 2244 2245 /* Caller must call svn_sleep_for_timestamps() */ 2246 *merge_b->use_sleep = TRUE; 2247 } 2248 2249 SVN_ERR(record_update_add(merge_b, local_abspath, svn_node_file, 2250 fb->add_is_replace, scratch_pool)); 2251 2252 return SVN_NO_ERROR; 2253} 2254 2255/* Compare the two sets of properties PROPS1 and PROPS2, ignoring the 2256 * "svn:mergeinfo" property, and noticing only "normal" props. Set *SAME to 2257 * true if the rest of the properties are identical or false if they differ. 2258 */ 2259static svn_error_t * 2260properties_same_p(svn_boolean_t *same, 2261 apr_hash_t *props1, 2262 apr_hash_t *props2, 2263 apr_pool_t *scratch_pool) 2264{ 2265 apr_array_header_t *prop_changes; 2266 int i, diffs; 2267 2268 /* Examine the properties that differ */ 2269 SVN_ERR(svn_prop_diffs(&prop_changes, props1, props2, scratch_pool)); 2270 diffs = 0; 2271 for (i = 0; i < prop_changes->nelts; i++) 2272 { 2273 const char *pname = APR_ARRAY_IDX(prop_changes, i, svn_prop_t).name; 2274 2275 /* Count the properties we're interested in; ignore the rest */ 2276 if (svn_wc_is_normal_prop(pname) 2277 && strcmp(pname, SVN_PROP_MERGEINFO) != 0) 2278 diffs++; 2279 } 2280 *same = (diffs == 0); 2281 return SVN_NO_ERROR; 2282} 2283 2284/* Compare the file OLDER_ABSPATH (together with its normal properties in 2285 * ORIGINAL_PROPS which may also contain WC props and entry props) with the 2286 * versioned file MINE_ABSPATH (together with its versioned properties). 2287 * Set *SAME to true if they are the same or false if they differ, ignoring 2288 * the "svn:mergeinfo" property, and ignoring differences in keyword 2289 * expansion and end-of-line style. */ 2290static svn_error_t * 2291files_same_p(svn_boolean_t *same, 2292 const char *older_abspath, 2293 apr_hash_t *original_props, 2294 const char *mine_abspath, 2295 svn_wc_context_t *wc_ctx, 2296 apr_pool_t *scratch_pool) 2297{ 2298 apr_hash_t *working_props; 2299 2300 SVN_ERR(svn_wc_prop_list2(&working_props, wc_ctx, mine_abspath, 2301 scratch_pool, scratch_pool)); 2302 2303 /* Compare the properties */ 2304 SVN_ERR(properties_same_p(same, original_props, working_props, 2305 scratch_pool)); 2306 if (*same) 2307 { 2308 svn_stream_t *mine_stream; 2309 svn_stream_t *older_stream; 2310 svn_opt_revision_t working_rev = { svn_opt_revision_working, { 0 } }; 2311 2312 /* Compare the file content, translating 'mine' to 'normal' form. */ 2313 if (svn_prop_get_value(working_props, SVN_PROP_SPECIAL) != NULL) 2314 SVN_ERR(svn_subst_read_specialfile(&mine_stream, mine_abspath, 2315 scratch_pool, scratch_pool)); 2316 else 2317 SVN_ERR(svn_client__get_normalized_stream(&mine_stream, wc_ctx, 2318 mine_abspath, &working_rev, 2319 FALSE, TRUE, NULL, NULL, 2320 scratch_pool, scratch_pool)); 2321 2322 SVN_ERR(svn_stream_open_readonly(&older_stream, older_abspath, 2323 scratch_pool, scratch_pool)); 2324 2325 SVN_ERR(svn_stream_contents_same2(same, mine_stream, older_stream, 2326 scratch_pool)); 2327 2328 } 2329 2330 return SVN_NO_ERROR; 2331} 2332 2333/* An svn_diff_tree_processor_t function. 2334 * 2335 * Called after merge_file_opened() when a node does exist in LEFT_SOURCE, but 2336 * no longer exists (or is replaced) in RIGHT_SOURCE. 2337 * 2338 * When a node is replaced instead of just added a separate opened+added will 2339 * be invoked after the current open+deleted. 2340 */ 2341static svn_error_t * 2342merge_file_deleted(const char *relpath, 2343 const svn_diff_source_t *left_source, 2344 const char *left_file, 2345 /*const*/ apr_hash_t *left_props, 2346 void *file_baton, 2347 const struct svn_diff_tree_processor_t *processor, 2348 apr_pool_t *scratch_pool) 2349{ 2350 merge_cmd_baton_t *merge_b = processor->baton; 2351 struct merge_file_baton_t *fb = file_baton; 2352 const char *local_abspath = svn_dirent_join(merge_b->target->abspath, 2353 relpath, scratch_pool); 2354 svn_boolean_t same; 2355 2356 SVN_ERR(mark_file_edited(merge_b, fb, local_abspath, scratch_pool)); 2357 2358 if (fb->shadowed) 2359 { 2360 if (fb->tree_conflict_reason == CONFLICT_REASON_NONE) 2361 { 2362 /* We haven't notified for this node yet: report a skip */ 2363 SVN_ERR(record_skip(merge_b, local_abspath, svn_node_file, 2364 svn_wc_notify_update_shadowed_delete, 2365 fb->skip_reason, fb->parent_baton, 2366 scratch_pool)); 2367 } 2368 2369 return SVN_NO_ERROR; 2370 } 2371 2372 /* Easy out: We are only applying mergeinfo differences. */ 2373 if (merge_b->record_only) 2374 { 2375 return SVN_NO_ERROR; 2376 } 2377 2378 /* If the files are identical, attempt deletion */ 2379 if (merge_b->force_delete) 2380 same = TRUE; 2381 else 2382 SVN_ERR(files_same_p(&same, left_file, left_props, 2383 local_abspath, merge_b->ctx->wc_ctx, 2384 scratch_pool)); 2385 2386 if (fb->parent_baton 2387 && fb->parent_baton->delete_state) 2388 { 2389 if (same) 2390 { 2391 /* Note that we checked this file */ 2392 store_path(fb->parent_baton->delete_state->compared_abspaths, 2393 local_abspath); 2394 } 2395 else 2396 { 2397 /* We found some modification. Parent should raise a tree conflict */ 2398 fb->parent_baton->delete_state->found_edit = TRUE; 2399 } 2400 2401 return SVN_NO_ERROR; 2402 } 2403 else if (same) 2404 { 2405 if (!merge_b->dry_run) 2406 SVN_ERR(svn_wc_delete4(merge_b->ctx->wc_ctx, local_abspath, 2407 FALSE /* keep_local */, FALSE /* unversioned */, 2408 merge_b->ctx->cancel_func, 2409 merge_b->ctx->cancel_baton, 2410 NULL, NULL /* no notify */, 2411 scratch_pool)); 2412 2413 /* Record that we might have deleted mergeinfo */ 2414 alloc_and_store_path(&merge_b->paths_with_deleted_mergeinfo, 2415 local_abspath, merge_b->pool); 2416 2417 /* And notify the deletion */ 2418 SVN_ERR(record_update_delete(merge_b, fb->parent_baton, local_abspath, 2419 svn_node_file, scratch_pool)); 2420 } 2421 else 2422 { 2423 /* The files differ, so raise a conflict instead of deleting */ 2424 2425 /* This is use case 5 described in the paper attached to issue 2426 * #2282. See also notes/tree-conflicts/detection.txt 2427 */ 2428 SVN_ERR(record_tree_conflict(merge_b, local_abspath, fb->parent_baton, 2429 svn_node_file, 2430 svn_wc_conflict_action_delete, 2431 svn_wc_conflict_reason_edited, 2432 NULL, TRUE, 2433 scratch_pool)); 2434 } 2435 2436 return SVN_NO_ERROR; 2437} 2438 2439/* An svn_diff_tree_processor_t function. 2440 2441 Called before either merge_dir_changed(), merge_dir_added(), 2442 merge_dir_deleted() or merge_dir_closed(), unless it sets *SKIP to TRUE. 2443 2444 After this call and before the close call, all descendants will receive 2445 their changes, unless *SKIP_CHILDREN is set to TRUE. 2446 2447 When *SKIP is TRUE, the diff driver avoids work on getting the details 2448 for the closing callbacks. 2449 2450 The SKIP and SKIP_DESCENDANTS work independantly. 2451 */ 2452static svn_error_t * 2453merge_dir_opened(void **new_dir_baton, 2454 svn_boolean_t *skip, 2455 svn_boolean_t *skip_children, 2456 const char *relpath, 2457 const svn_diff_source_t *left_source, 2458 const svn_diff_source_t *right_source, 2459 const svn_diff_source_t *copyfrom_source, 2460 void *parent_dir_baton, 2461 const struct svn_diff_tree_processor_t *processor, 2462 apr_pool_t *result_pool, 2463 apr_pool_t *scratch_pool) 2464{ 2465 merge_cmd_baton_t *merge_b = processor->baton; 2466 struct merge_dir_baton_t *db; 2467 struct merge_dir_baton_t *pdb = parent_dir_baton; 2468 2469 const char *local_abspath = svn_dirent_join(merge_b->target->abspath, 2470 relpath, scratch_pool); 2471 2472 db = apr_pcalloc(result_pool, sizeof(*db)); 2473 db->pool = result_pool; 2474 db->tree_conflict_reason = CONFLICT_REASON_NONE; 2475 db->tree_conflict_action = svn_wc_conflict_action_edit; 2476 db->skip_reason = svn_wc_notify_state_unknown; 2477 2478 *new_dir_baton = db; 2479 2480 if (pdb) 2481 { 2482 db->parent_baton = pdb; 2483 db->shadowed = pdb->shadowed; 2484 db->skip_reason = pdb->skip_reason; 2485 } 2486 2487 if (db->shadowed) 2488 { 2489 /* An ancestor is tree conflicted. Nothing to do here. */ 2490 if (! left_source) 2491 db->added = TRUE; 2492 } 2493 else if (left_source != NULL) 2494 { 2495 /* Node is expected to be a directory. */ 2496 svn_node_kind_t kind; 2497 svn_boolean_t is_deleted; 2498 svn_boolean_t excluded; 2499 svn_depth_t parent_depth; 2500 2501 if (! right_source) 2502 db->tree_conflict_action = svn_wc_conflict_action_delete; 2503 2504 /* Check for an obstructed or missing node on disk. */ 2505 { 2506 svn_wc_notify_state_t obstr_state; 2507 SVN_ERR(perform_obstruction_check(&obstr_state, &is_deleted, &excluded, 2508 &kind, &parent_depth, 2509 merge_b, local_abspath, 2510 scratch_pool)); 2511 2512 if (obstr_state != svn_wc_notify_state_inapplicable) 2513 { 2514 db->shadowed = TRUE; 2515 2516 if (obstr_state == svn_wc_notify_state_obstructed) 2517 { 2518 svn_boolean_t is_wcroot; 2519 2520 SVN_ERR(svn_wc_check_root(&is_wcroot, NULL, NULL, 2521 merge_b->ctx->wc_ctx, 2522 local_abspath, scratch_pool)); 2523 2524 if (is_wcroot) 2525 { 2526 db->tree_conflict_reason = CONFLICT_REASON_SKIP_WC; 2527 return SVN_NO_ERROR; 2528 } 2529 } 2530 2531 db->tree_conflict_reason = CONFLICT_REASON_SKIP; 2532 db->skip_reason = obstr_state; 2533 2534 if (! right_source) 2535 { 2536 *skip = *skip_children = TRUE; 2537 SVN_ERR(mark_dir_edited(merge_b, db, local_abspath, 2538 scratch_pool)); 2539 } 2540 2541 return SVN_NO_ERROR; 2542 } 2543 2544 if (is_deleted) 2545 kind = svn_node_none; 2546 } 2547 2548 if (kind == svn_node_none) 2549 { 2550 db->shadowed = TRUE; 2551 2552 /* If this is not the merge target and the parent is too shallow to 2553 contain this directory, and the directory is not presen 2554 via exclusion or depth filtering, skip it instead of recording 2555 a tree conflict. 2556 2557 Non-inheritable mergeinfo will be recorded, allowing 2558 future merges into non-shallow working copies to merge 2559 changes we missed this time around. */ 2560 if (pdb && (excluded 2561 || (parent_depth != svn_depth_unknown && 2562 parent_depth < svn_depth_immediates))) 2563 { 2564 db->shadowed = TRUE; 2565 2566 db->tree_conflict_reason = CONFLICT_REASON_SKIP; 2567 db->skip_reason = svn_wc_notify_state_missing; 2568 2569 return SVN_NO_ERROR; 2570 } 2571 2572 if (is_deleted) 2573 db->tree_conflict_reason = svn_wc_conflict_reason_deleted; 2574 else 2575 db->tree_conflict_reason = svn_wc_conflict_reason_missing; 2576 2577 /* ### To avoid breaking tests */ 2578 *skip = TRUE; 2579 *skip_children = TRUE; 2580 SVN_ERR(mark_dir_edited(merge_b, db, local_abspath, scratch_pool)); 2581 return SVN_NO_ERROR; 2582 /* ### /avoid breaking tests */ 2583 } 2584 else if (kind != svn_node_dir) 2585 { 2586 db->shadowed = TRUE; 2587 2588 db->tree_conflict_reason = svn_wc_conflict_reason_obstructed; 2589 2590 /* ### To avoid breaking tests */ 2591 *skip = TRUE; 2592 *skip_children = TRUE; 2593 SVN_ERR(mark_dir_edited(merge_b, db, local_abspath, scratch_pool)); 2594 return SVN_NO_ERROR; 2595 /* ### /avoid breaking tests */ 2596 } 2597 2598 if (! right_source) 2599 { 2600 /* We want to delete the directory */ 2601 /* Mark PB edited now? */ 2602 db->tree_conflict_action = svn_wc_conflict_action_delete; 2603 SVN_ERR(mark_dir_edited(merge_b, db, local_abspath, scratch_pool)); 2604 2605 if (db->shadowed) 2606 { 2607 *skip_children = TRUE; 2608 return SVN_NO_ERROR; /* Already set a tree conflict */ 2609 } 2610 2611 db->delete_state = (pdb != NULL) ? pdb->delete_state : NULL; 2612 2613 if (db->delete_state && db->delete_state->found_edit) 2614 { 2615 /* A sibling found a conflict. Done. */ 2616 *skip = TRUE; 2617 *skip_children = TRUE; 2618 } 2619 else if (merge_b->force_delete) 2620 { 2621 /* No comparison necessary */ 2622 *skip_children = TRUE; 2623 } 2624 else if (! db->delete_state) 2625 { 2626 /* Start descendant comparison */ 2627 db->delete_state = apr_pcalloc(db->pool, 2628 sizeof(*db->delete_state)); 2629 2630 db->delete_state->del_root = db; 2631 db->delete_state->compared_abspaths = apr_hash_make(db->pool); 2632 } 2633 } 2634 } 2635 else 2636 { 2637 const svn_wc_conflict_description2_t *old_tc = NULL; 2638 2639 /* The node doesn't exist pre-merge: We have an addition */ 2640 db->added = TRUE; 2641 db->tree_conflict_action = svn_wc_conflict_action_add; 2642 2643 if (pdb && pdb->pending_deletes 2644 && svn_hash_gets(pdb->pending_deletes, local_abspath)) 2645 { 2646 db->add_is_replace = TRUE; 2647 db->tree_conflict_action = svn_wc_conflict_action_replace; 2648 2649 svn_hash_sets(pdb->pending_deletes, local_abspath, NULL); 2650 } 2651 2652 if (pdb 2653 && pdb->new_tree_conflicts 2654 && (old_tc = svn_hash_gets(pdb->new_tree_conflicts, local_abspath))) 2655 { 2656 db->tree_conflict_action = svn_wc_conflict_action_replace; 2657 db->tree_conflict_reason = old_tc->reason; 2658 2659 if (old_tc->reason == svn_wc_conflict_reason_deleted 2660 || old_tc->reason == svn_wc_conflict_reason_moved_away) 2661 { 2662 /* Issue #3806: Incoming replacements on local deletes produce 2663 inconsistent result. 2664 2665 In this specific case we can continue applying the add part 2666 of the replacement. */ 2667 } 2668 else 2669 { 2670 *skip = TRUE; 2671 *skip_children = TRUE; 2672 2673 /* Update the tree conflict to store that this is a replace */ 2674 SVN_ERR(record_tree_conflict(merge_b, local_abspath, pdb, 2675 svn_node_dir, 2676 db->tree_conflict_action, 2677 db->tree_conflict_reason, 2678 old_tc, FALSE, 2679 scratch_pool)); 2680 2681 return SVN_NO_ERROR; 2682 } 2683 } 2684 2685 if (! (merge_b->dry_run 2686 && ((pdb && pdb->added) || db->add_is_replace))) 2687 { 2688 svn_wc_notify_state_t obstr_state; 2689 svn_node_kind_t kind; 2690 svn_boolean_t is_deleted; 2691 2692 SVN_ERR(perform_obstruction_check(&obstr_state, &is_deleted, NULL, 2693 &kind, NULL, 2694 merge_b, local_abspath, 2695 scratch_pool)); 2696 2697 /* In this case of adding a directory, we have an exception to the 2698 * usual "skip if it's inconsistent" rule. If the directory exists 2699 * on disk unexpectedly, we simply make it versioned, because we can 2700 * do so without risk of destroying data. Only skip if it is 2701 * versioned but unexpectedly missing from disk, or is unversioned 2702 * but obstructed by a node of the wrong kind. */ 2703 if (obstr_state == svn_wc_notify_state_obstructed 2704 && (is_deleted || kind == svn_node_none)) 2705 { 2706 svn_node_kind_t disk_kind; 2707 2708 SVN_ERR(svn_io_check_path(local_abspath, &disk_kind, 2709 scratch_pool)); 2710 2711 if (disk_kind == svn_node_dir) 2712 { 2713 obstr_state = svn_wc_notify_state_inapplicable; 2714 db->add_existing = TRUE; /* Take over existing directory */ 2715 } 2716 } 2717 2718 if (obstr_state != svn_wc_notify_state_inapplicable) 2719 { 2720 /* Skip the obstruction */ 2721 db->shadowed = TRUE; 2722 db->tree_conflict_reason = CONFLICT_REASON_SKIP; 2723 db->skip_reason = obstr_state; 2724 } 2725 else if (kind != svn_node_none && !is_deleted) 2726 { 2727 /* Set a tree conflict */ 2728 db->shadowed = TRUE; 2729 db->tree_conflict_reason = svn_wc_conflict_reason_obstructed; 2730 2731 if ((merge_b->merge_source.ancestral || merge_b->reintegrate_merge) 2732 && !(pdb && pdb->shadowed)) 2733 { 2734 store_path(merge_b->skipped_abspaths, local_abspath); 2735 } 2736 } 2737 } 2738 2739 /* Handle pending conflicts */ 2740 SVN_ERR(mark_dir_edited(merge_b, db, local_abspath, scratch_pool)); 2741 2742 if (db->shadowed) 2743 { 2744 /* Notified and done. Skip children? */ 2745 } 2746 else if (merge_b->record_only) 2747 { 2748 /* Ok, we are done for this node and its descendants */ 2749 *skip = TRUE; 2750 *skip_children = TRUE; 2751 } 2752 else if (! merge_b->dry_run) 2753 { 2754 /* Create the directory on disk, to allow descendants to be added */ 2755 if (! db->add_existing) 2756 SVN_ERR(svn_io_dir_make(local_abspath, APR_OS_DEFAULT, 2757 scratch_pool)); 2758 2759 if (old_tc) 2760 { 2761 /* svn_wc_add4 and svn_wc_add_from_disk2 can't add a node 2762 over an existing tree conflict */ 2763 2764 /* ### These functions should take some tree conflict argument 2765 and allow overwriting the tc when one is passed */ 2766 2767 SVN_ERR(svn_wc__del_tree_conflict(merge_b->ctx->wc_ctx, 2768 local_abspath, 2769 scratch_pool)); 2770 } 2771 2772 if (merge_b->same_repos) 2773 { 2774 const char *original_url; 2775 2776 original_url = svn_path_url_add_component2( 2777 merge_b->merge_source.loc2->url, 2778 relpath, scratch_pool); 2779 2780 /* Limitation (aka HACK): 2781 We create a newly added directory with an original URL and 2782 revision as that in the repository, but without its properties 2783 and children. 2784 2785 When the merge is cancelled before the final dir_added(), the 2786 copy won't really represent the in-repository state of the node. 2787 */ 2788 SVN_ERR(svn_wc_add4(merge_b->ctx->wc_ctx, local_abspath, 2789 svn_depth_infinity, 2790 original_url, 2791 right_source->revision, 2792 merge_b->ctx->cancel_func, 2793 merge_b->ctx->cancel_baton, 2794 NULL, NULL /* no notify! */, 2795 scratch_pool)); 2796 } 2797 else 2798 { 2799 SVN_ERR(svn_wc_add_from_disk2(merge_b->ctx->wc_ctx, local_abspath, 2800 apr_hash_make(scratch_pool), 2801 NULL, NULL /* no notify! */, 2802 scratch_pool)); 2803 } 2804 2805 if (old_tc != NULL) 2806 { 2807 /* ### Should be atomic with svn_wc_add(4|_from_disk2)() */ 2808 SVN_ERR(record_tree_conflict(merge_b, local_abspath, pdb, 2809 svn_node_dir, 2810 db->tree_conflict_action, 2811 db->tree_conflict_reason, 2812 old_tc, FALSE, 2813 scratch_pool)); 2814 } 2815 } 2816 2817 if (! db->shadowed && !merge_b->record_only) 2818 SVN_ERR(record_update_add(merge_b, local_abspath, svn_node_dir, 2819 db->add_is_replace, scratch_pool)); 2820 } 2821 return SVN_NO_ERROR; 2822} 2823 2824/* An svn_diff_tree_processor_t function. 2825 * 2826 * Called after merge_dir_opened() when a node exists in both the left and 2827 * right source, but has its properties changed inbetween. 2828 * 2829 * After the merge_dir_opened() but before the call to this merge_dir_changed() 2830 * function all descendants will have been updated. 2831 */ 2832static svn_error_t * 2833merge_dir_changed(const char *relpath, 2834 const svn_diff_source_t *left_source, 2835 const svn_diff_source_t *right_source, 2836 /*const*/ apr_hash_t *left_props, 2837 /*const*/ apr_hash_t *right_props, 2838 const apr_array_header_t *prop_changes, 2839 void *dir_baton, 2840 const struct svn_diff_tree_processor_t *processor, 2841 apr_pool_t *scratch_pool) 2842{ 2843 merge_cmd_baton_t *merge_b = processor->baton; 2844 struct merge_dir_baton_t *db = dir_baton; 2845 const apr_array_header_t *props; 2846 const char *local_abspath = svn_dirent_join(merge_b->target->abspath, 2847 relpath, scratch_pool); 2848 2849 SVN_ERR(handle_pending_notifications(merge_b, db, scratch_pool)); 2850 2851 SVN_ERR(mark_dir_edited(merge_b, db, local_abspath, scratch_pool)); 2852 2853 if (db->shadowed) 2854 { 2855 if (db->tree_conflict_reason == CONFLICT_REASON_NONE) 2856 { 2857 /* We haven't notified for this node yet: report a skip */ 2858 SVN_ERR(record_skip(merge_b, local_abspath, svn_node_dir, 2859 svn_wc_notify_update_shadowed_update, 2860 db->skip_reason, db->parent_baton, 2861 scratch_pool)); 2862 } 2863 2864 return SVN_NO_ERROR; 2865 } 2866 2867 SVN_ERR(prepare_merge_props_changed(&props, local_abspath, prop_changes, 2868 merge_b, scratch_pool, scratch_pool)); 2869 2870 if (props->nelts) 2871 { 2872 const svn_wc_conflict_version_t *left; 2873 const svn_wc_conflict_version_t *right; 2874 svn_client_ctx_t *ctx = merge_b->ctx; 2875 svn_wc_notify_state_t prop_state; 2876 2877 SVN_ERR(make_conflict_versions(&left, &right, local_abspath, 2878 svn_node_dir, &merge_b->merge_source, 2879 merge_b->target, 2880 scratch_pool, scratch_pool)); 2881 2882 SVN_ERR(svn_wc_merge_props3(&prop_state, ctx->wc_ctx, local_abspath, 2883 left, right, 2884 left_props, props, 2885 merge_b->dry_run, 2886 NULL, NULL, 2887 ctx->cancel_func, ctx->cancel_baton, 2888 scratch_pool)); 2889 2890 if (prop_state == svn_wc_notify_state_conflicted) 2891 { 2892 alloc_and_store_path(&merge_b->conflicted_paths, local_abspath, 2893 merge_b->pool); 2894 } 2895 2896 if (prop_state == svn_wc_notify_state_conflicted 2897 || prop_state == svn_wc_notify_state_merged 2898 || prop_state == svn_wc_notify_state_changed) 2899 { 2900 SVN_ERR(record_update_update(merge_b, local_abspath, svn_node_file, 2901 svn_wc_notify_state_inapplicable, 2902 prop_state, scratch_pool)); 2903 } 2904 } 2905 2906 return SVN_NO_ERROR; 2907} 2908 2909 2910/* An svn_diff_tree_processor_t function. 2911 * 2912 * Called after merge_dir_opened() when a node doesn't exist in LEFT_SOURCE, 2913 * but does in RIGHT_SOURCE. After the merge_dir_opened() but before the call 2914 * to this merge_dir_added() function all descendants will have been added. 2915 * 2916 * When a node is replaced instead of just added a separate opened+deleted will 2917 * be invoked before the current open+added. 2918 */ 2919static svn_error_t * 2920merge_dir_added(const char *relpath, 2921 const svn_diff_source_t *copyfrom_source, 2922 const svn_diff_source_t *right_source, 2923 /*const*/ apr_hash_t *copyfrom_props, 2924 /*const*/ apr_hash_t *right_props, 2925 void *dir_baton, 2926 const struct svn_diff_tree_processor_t *processor, 2927 apr_pool_t *scratch_pool) 2928{ 2929 merge_cmd_baton_t *merge_b = processor->baton; 2930 struct merge_dir_baton_t *db = dir_baton; 2931 const char *local_abspath = svn_dirent_join(merge_b->target->abspath, 2932 relpath, scratch_pool); 2933 2934 /* For consistency; usually a no-op from _dir_added() */ 2935 SVN_ERR(handle_pending_notifications(merge_b, db, scratch_pool)); 2936 SVN_ERR(mark_dir_edited(merge_b, db, local_abspath, scratch_pool)); 2937 2938 if (db->shadowed) 2939 { 2940 if (db->tree_conflict_reason == CONFLICT_REASON_NONE) 2941 { 2942 /* We haven't notified for this node yet: report a skip */ 2943 SVN_ERR(record_skip(merge_b, local_abspath, svn_node_dir, 2944 svn_wc_notify_update_shadowed_add, 2945 db->skip_reason, db->parent_baton, 2946 scratch_pool)); 2947 } 2948 2949 return SVN_NO_ERROR; 2950 } 2951 2952 SVN_ERR_ASSERT( 2953 db->edited /* Marked edited from merge_open_dir() */ 2954 && ! merge_b->record_only /* Skip details from merge_open_dir() */ 2955 ); 2956 2957 if ((merge_b->merge_source.ancestral || merge_b->reintegrate_merge) 2958 && ( !db->parent_baton || !db->parent_baton->added)) 2959 { 2960 /* Store the roots of added subtrees */ 2961 store_path(merge_b->added_abspaths, local_abspath); 2962 } 2963 2964 if (merge_b->same_repos) 2965 { 2966 /* When the directory was added in merge_dir_added() we didn't update its 2967 pristine properties. Instead we receive the property changes later and 2968 apply them in this function. 2969 2970 If we would apply them as changes (such as before fixing issue #3405), 2971 we would see the unmodified properties as local changes, and the 2972 pristine properties would be out of sync with what the repository 2973 expects for this directory. 2974 2975 Instead of doing that we now simply set the properties as the pristine 2976 properties via a private libsvn_wc api. 2977 */ 2978 2979 const char *copyfrom_url; 2980 svn_revnum_t copyfrom_rev; 2981 const char *parent_abspath; 2982 const char *child; 2983 2984 /* Creating a hash containing regular and entry props */ 2985 apr_hash_t *new_pristine_props = right_props; 2986 2987 parent_abspath = svn_dirent_dirname(local_abspath, scratch_pool); 2988 child = svn_dirent_is_child(merge_b->target->abspath, local_abspath, NULL); 2989 SVN_ERR_ASSERT(child != NULL); 2990 2991 copyfrom_url = svn_path_url_add_component2(merge_b->merge_source.loc2->url, 2992 child, scratch_pool); 2993 copyfrom_rev = right_source->revision; 2994 2995 SVN_ERR(check_repos_match(merge_b->target, parent_abspath, copyfrom_url, 2996 scratch_pool)); 2997 2998 if (!merge_b->dry_run) 2999 { 3000 SVN_ERR(svn_wc__complete_directory_add(merge_b->ctx->wc_ctx, 3001 local_abspath, 3002 new_pristine_props, 3003 copyfrom_url, copyfrom_rev, 3004 scratch_pool)); 3005 } 3006 3007 if (svn_hash_gets(new_pristine_props, SVN_PROP_MERGEINFO)) 3008 { 3009 alloc_and_store_path(&merge_b->paths_with_new_mergeinfo, 3010 local_abspath, merge_b->pool); 3011 } 3012 } 3013 else 3014 { 3015 apr_array_header_t *regular_props; 3016 apr_hash_t *new_props; 3017 svn_wc_notify_state_t prop_state; 3018 3019 SVN_ERR(svn_categorize_props(svn_prop_hash_to_array(right_props, 3020 scratch_pool), 3021 NULL, NULL, ®ular_props, scratch_pool)); 3022 3023 new_props = svn_prop_array_to_hash(regular_props, scratch_pool); 3024 3025 svn_hash_sets(new_props, SVN_PROP_MERGEINFO, NULL); 3026 3027 /* ### What is the easiest way to set new_props on LOCAL_ABSPATH? 3028 3029 ### This doesn't need a merge as we just added the node 3030 ### (or installed a tree conflict and skipped this node)*/ 3031 3032 SVN_ERR(svn_wc_merge_props3(&prop_state, merge_b->ctx->wc_ctx, 3033 local_abspath, 3034 NULL, NULL, 3035 apr_hash_make(scratch_pool), 3036 svn_prop_hash_to_array(new_props, 3037 scratch_pool), 3038 merge_b->dry_run, 3039 NULL, NULL, 3040 merge_b->ctx->cancel_func, 3041 merge_b->ctx->cancel_baton, 3042 scratch_pool)); 3043 if (prop_state == svn_wc_notify_state_conflicted) 3044 { 3045 alloc_and_store_path(&merge_b->conflicted_paths, local_abspath, 3046 merge_b->pool); 3047 } 3048 } 3049 3050 return SVN_NO_ERROR; 3051} 3052 3053/* Helper for merge_dir_deleted. Implement svn_wc_status_func4_t */ 3054static svn_error_t * 3055verify_touched_by_del_check(void *baton, 3056 const char *local_abspath, 3057 const svn_wc_status3_t *status, 3058 apr_pool_t *scratch_pool) 3059{ 3060 struct dir_delete_baton_t *delb = baton; 3061 3062 if (svn_hash_gets(delb->compared_abspaths, local_abspath)) 3063 return SVN_NO_ERROR; 3064 3065 switch (status->node_status) 3066 { 3067 case svn_wc_status_deleted: 3068 case svn_wc_status_ignored: 3069 case svn_wc_status_none: 3070 return SVN_NO_ERROR; 3071 3072 default: 3073 delb->found_edit = TRUE; 3074 return svn_error_create(SVN_ERR_CEASE_INVOCATION, NULL, NULL); 3075 } 3076} 3077 3078/* An svn_diff_tree_processor_t function. 3079 * 3080 * Called after merge_dir_opened() when a node existed only in the left source. 3081 * 3082 * After the merge_dir_opened() but before the call to this merge_dir_deleted() 3083 * function all descendants that existed in left_source will have been deleted. 3084 * 3085 * If this node is replaced, an _opened() followed by a matching _add() will 3086 * be invoked after this function. 3087 */ 3088static svn_error_t * 3089merge_dir_deleted(const char *relpath, 3090 const svn_diff_source_t *left_source, 3091 /*const*/ apr_hash_t *left_props, 3092 void *dir_baton, 3093 const struct svn_diff_tree_processor_t *processor, 3094 apr_pool_t *scratch_pool) 3095{ 3096 merge_cmd_baton_t *merge_b = processor->baton; 3097 struct merge_dir_baton_t *db = dir_baton; 3098 const char *local_abspath = svn_dirent_join(merge_b->target->abspath, 3099 relpath, scratch_pool); 3100 svn_boolean_t same; 3101 apr_hash_t *working_props; 3102 3103 SVN_ERR(handle_pending_notifications(merge_b, db, scratch_pool)); 3104 SVN_ERR(mark_dir_edited(merge_b, db, local_abspath, scratch_pool)); 3105 3106 if (db->shadowed) 3107 { 3108 if (db->tree_conflict_reason == CONFLICT_REASON_NONE) 3109 { 3110 /* We haven't notified for this node yet: report a skip */ 3111 SVN_ERR(record_skip(merge_b, local_abspath, svn_node_dir, 3112 svn_wc_notify_update_shadowed_delete, 3113 db->skip_reason, db->parent_baton, 3114 scratch_pool)); 3115 } 3116 3117 return SVN_NO_ERROR; 3118 } 3119 3120 /* Easy out: We are only applying mergeinfo differences. */ 3121 if (merge_b->record_only) 3122 { 3123 return SVN_NO_ERROR; 3124 } 3125 3126 SVN_ERR(svn_wc_prop_list2(&working_props, 3127 merge_b->ctx->wc_ctx, local_abspath, 3128 scratch_pool, scratch_pool)); 3129 3130 if (merge_b->force_delete) 3131 { 3132 /* In this legacy mode we just assume that a directory delete 3133 matches any directory. db->delete_state is NULL */ 3134 same = TRUE; 3135 } 3136 else 3137 { 3138 struct dir_delete_baton_t *delb; 3139 3140 /* Compare the properties */ 3141 SVN_ERR(properties_same_p(&same, left_props, working_props, 3142 scratch_pool)); 3143 delb = db->delete_state; 3144 assert(delb != NULL); 3145 3146 if (! same) 3147 { 3148 delb->found_edit = TRUE; 3149 } 3150 else 3151 { 3152 store_path(delb->compared_abspaths, local_abspath); 3153 } 3154 3155 if (delb->del_root != db) 3156 return SVN_NO_ERROR; 3157 3158 if (delb->found_edit) 3159 same = FALSE; 3160 else 3161 { 3162 apr_array_header_t *ignores; 3163 svn_error_t *err; 3164 same = TRUE; 3165 3166 SVN_ERR(svn_wc_get_default_ignores(&ignores, merge_b->ctx->config, 3167 scratch_pool)); 3168 3169 /* None of the descendants was modified, but maybe there are 3170 descendants we haven't walked? 3171 3172 Note that we aren't interested in changes, as we already verified 3173 changes in the paths touched by the merge. And the existence of 3174 other paths is enough to mark the directory edited */ 3175 err = svn_wc_walk_status(merge_b->ctx->wc_ctx, local_abspath, 3176 svn_depth_infinity, TRUE /* get-all */, 3177 FALSE /* no-ignore */, 3178 TRUE /* ignore-text-mods */, ignores, 3179 verify_touched_by_del_check, delb, 3180 merge_b->ctx->cancel_func, 3181 merge_b->ctx->cancel_baton, 3182 scratch_pool); 3183 3184 if (err) 3185 { 3186 if (err->apr_err != SVN_ERR_CEASE_INVOCATION) 3187 return svn_error_trace(err); 3188 3189 svn_error_clear(err); 3190 } 3191 3192 same = ! delb->found_edit; 3193 } 3194 } 3195 3196 if (same && !merge_b->dry_run) 3197 { 3198 svn_error_t *err; 3199 3200 err = svn_wc_delete4(merge_b->ctx->wc_ctx, local_abspath, 3201 FALSE /* keep_local */, FALSE /* unversioned */, 3202 merge_b->ctx->cancel_func, 3203 merge_b->ctx->cancel_baton, 3204 NULL, NULL /* no notify */, 3205 scratch_pool); 3206 3207 if (err) 3208 { 3209 if (err->apr_err != SVN_ERR_WC_LEFT_LOCAL_MOD) 3210 return svn_error_trace(err); 3211 3212 svn_error_clear(err); 3213 same = FALSE; 3214 } 3215 } 3216 3217 if (! same) 3218 { 3219 /* If the attempt to delete an existing directory failed, 3220 * the directory has local modifications (e.g. locally added 3221 * files, or property changes). Flag a tree conflict. */ 3222 3223 /* This handles use case 5 described in the paper attached to issue 3224 * #2282. See also notes/tree-conflicts/detection.txt 3225 */ 3226 SVN_ERR(record_tree_conflict(merge_b, local_abspath, db->parent_baton, 3227 svn_node_dir, 3228 svn_wc_conflict_action_delete, 3229 svn_wc_conflict_reason_edited, 3230 NULL, TRUE, 3231 scratch_pool)); 3232 } 3233 else 3234 { 3235 /* Record that we might have deleted mergeinfo */ 3236 if (working_props 3237 && svn_hash_gets(working_props, SVN_PROP_MERGEINFO)) 3238 { 3239 alloc_and_store_path(&merge_b->paths_with_deleted_mergeinfo, 3240 local_abspath, merge_b->pool); 3241 } 3242 3243 SVN_ERR(record_update_delete(merge_b, db->parent_baton, local_abspath, 3244 svn_node_dir, scratch_pool)); 3245 } 3246 3247 return SVN_NO_ERROR; 3248} 3249 3250/* An svn_diff_tree_processor_t function. 3251 * 3252 * Called after merge_dir_opened() when a node itself didn't change between 3253 * the left and right source. 3254 * 3255 * After the merge_dir_opened() but before the call to this merge_dir_closed() 3256 * function all descendants will have been processed. 3257 */ 3258static svn_error_t * 3259merge_dir_closed(const char *relpath, 3260 const svn_diff_source_t *left_source, 3261 const svn_diff_source_t *right_source, 3262 void *dir_baton, 3263 const struct svn_diff_tree_processor_t *processor, 3264 apr_pool_t *scratch_pool) 3265{ 3266 merge_cmd_baton_t *merge_b = processor->baton; 3267 struct merge_dir_baton_t *db = dir_baton; 3268 3269 SVN_ERR(handle_pending_notifications(merge_b, db, scratch_pool)); 3270 3271 return SVN_NO_ERROR; 3272} 3273 3274/* An svn_diff_tree_processor_t function. 3275 3276 Called when the diff driver wants to report an absent path. 3277 3278 In case of merges this happens when the diff encounters a server-excluded 3279 path. 3280 3281 We register a skipped path, which will make parent mergeinfo non- 3282 inheritable. This ensures that a future merge might see these skipped 3283 changes as eligable for merging. 3284 3285 For legacy reasons we also notify the path as skipped. 3286 */ 3287static svn_error_t * 3288merge_node_absent(const char *relpath, 3289 void *dir_baton, 3290 const svn_diff_tree_processor_t *processor, 3291 apr_pool_t *scratch_pool) 3292{ 3293 merge_cmd_baton_t *merge_b = processor->baton; 3294 struct merge_dir_baton_t *db = dir_baton; 3295 3296 const char *local_abspath = svn_dirent_join(merge_b->target->abspath, 3297 relpath, scratch_pool); 3298 3299 SVN_ERR(record_skip(merge_b, local_abspath, svn_node_unknown, 3300 svn_wc_notify_skip, svn_wc_notify_state_missing, 3301 db, scratch_pool)); 3302 3303 return SVN_NO_ERROR; 3304} 3305 3306/*-----------------------------------------------------------------------*/ 3307 3308/*** Merge Notification ***/ 3309 3310 3311/* Finds a nearest ancestor in CHILDREN_WITH_MERGEINFO for LOCAL_ABSPATH. If 3312 PATH_IS_OWN_ANCESTOR is TRUE then a child in CHILDREN_WITH_MERGEINFO 3313 where child->abspath == PATH is considered PATH's ancestor. If FALSE, 3314 then child->abspath must be a proper ancestor of PATH. 3315 3316 CHILDREN_WITH_MERGEINFO is expected to be sorted in Depth first 3317 order of path. */ 3318static svn_client__merge_path_t * 3319find_nearest_ancestor(const apr_array_header_t *children_with_mergeinfo, 3320 svn_boolean_t path_is_own_ancestor, 3321 const char *local_abspath) 3322{ 3323 int i; 3324 3325 SVN_ERR_ASSERT_NO_RETURN(children_with_mergeinfo != NULL); 3326 3327 for (i = children_with_mergeinfo->nelts - 1; i >= 0 ; i--) 3328 { 3329 svn_client__merge_path_t *child = 3330 APR_ARRAY_IDX(children_with_mergeinfo, i, svn_client__merge_path_t *); 3331 3332 if (svn_dirent_is_ancestor(child->abspath, local_abspath) 3333 && (path_is_own_ancestor 3334 || strcmp(child->abspath, local_abspath) != 0)) 3335 return child; 3336 } 3337 return NULL; 3338} 3339 3340/* Find the highest level path in a merge target (possibly the merge target 3341 itself) to use in a merge notification header. 3342 3343 Return the svn_client__merge_path_t * representing the most distant 3344 ancestor in CHILDREN_WITH_MERGEINFO of LOCAL_ABSPATH where said 3345 ancestor's first remaining ranges element (per the REMAINING_RANGES 3346 member of the ancestor) intersect with the first remaining ranges element 3347 for every intermediate ancestor svn_client__merge_path_t * of 3348 LOCAL_ABSPATH. If no such ancestor is found return NULL. 3349 3350 If the remaining ranges of the elements in CHILDREN_WITH_MERGEINFO 3351 represent a forward merge, then set *START to the oldest revision found 3352 in any of the intersecting ancestors and *END to the youngest revision 3353 found. If the remaining ranges of the elements in CHILDREN_WITH_MERGEINFO 3354 represent a reverse merge, then set *START to the youngest revision 3355 found and *END to the oldest revision found. If no ancestors are found 3356 then set *START and *END to SVN_INVALID_REVNUM. 3357 3358 If PATH_IS_OWN_ANCESTOR is TRUE then a child in CHILDREN_WITH_MERGEINFO 3359 where child->abspath == PATH is considered PATH's ancestor. If FALSE, 3360 then child->abspath must be a proper ancestor of PATH. 3361 3362 See the CHILDREN_WITH_MERGEINFO ARRAY global comment for more 3363 information. */ 3364static svn_client__merge_path_t * 3365find_nearest_ancestor_with_intersecting_ranges( 3366 svn_revnum_t *start, 3367 svn_revnum_t *end, 3368 const apr_array_header_t *children_with_mergeinfo, 3369 svn_boolean_t path_is_own_ancestor, 3370 const char *local_abspath) 3371{ 3372 int i; 3373 svn_client__merge_path_t *nearest_ancestor = NULL; 3374 3375 *start = SVN_INVALID_REVNUM; 3376 *end = SVN_INVALID_REVNUM; 3377 3378 SVN_ERR_ASSERT_NO_RETURN(children_with_mergeinfo != NULL); 3379 3380 for (i = children_with_mergeinfo->nelts - 1; i >= 0 ; i--) 3381 { 3382 svn_client__merge_path_t *child = 3383 APR_ARRAY_IDX(children_with_mergeinfo, i, svn_client__merge_path_t *); 3384 3385 if (svn_dirent_is_ancestor(child->abspath, local_abspath) 3386 && (path_is_own_ancestor 3387 || strcmp(child->abspath, local_abspath) != 0)) 3388 { 3389 if (nearest_ancestor == NULL) 3390 { 3391 /* Found an ancestor. */ 3392 nearest_ancestor = child; 3393 3394 if (child->remaining_ranges) 3395 { 3396 svn_merge_range_t *r1 = APR_ARRAY_IDX( 3397 child->remaining_ranges, 0, svn_merge_range_t *); 3398 *start = r1->start; 3399 *end = r1->end; 3400 } 3401 else 3402 { 3403 /* If CHILD->REMAINING_RANGES is null then LOCAL_ABSPATH 3404 is inside an absent subtree in the merge target. */ 3405 *start = SVN_INVALID_REVNUM; 3406 *end = SVN_INVALID_REVNUM; 3407 break; 3408 } 3409 } 3410 else 3411 { 3412 /* We'e found another ancestor for LOCAL_ABSPATH. Do its 3413 first remaining range intersect with the previously 3414 found ancestor? */ 3415 svn_merge_range_t *r1 = 3416 APR_ARRAY_IDX(nearest_ancestor->remaining_ranges, 0, 3417 svn_merge_range_t *); 3418 svn_merge_range_t *r2 = 3419 APR_ARRAY_IDX(child->remaining_ranges, 0, 3420 svn_merge_range_t *); 3421 3422 if (r1 && r2) 3423 { 3424 svn_merge_range_t range1; 3425 svn_merge_range_t range2; 3426 svn_boolean_t reverse_merge = r1->start > r2->end; 3427 3428 /* Flip endpoints if this is a reverse merge. */ 3429 if (reverse_merge) 3430 { 3431 range1.start = r1->end; 3432 range1.end = r1->start; 3433 range2.start = r2->end; 3434 range2.end = r2->start; 3435 } 3436 else 3437 { 3438 range1.start = r1->start; 3439 range1.end = r1->end; 3440 range2.start = r2->start; 3441 range2.end = r2->end; 3442 } 3443 3444 if (range1.start < range2.end && range2.start < range1.end) 3445 { 3446 *start = reverse_merge ? 3447 MAX(r1->start, r2->start) : MIN(r1->start, r2->start); 3448 *end = reverse_merge ? 3449 MIN(r1->end, r2->end) : MAX(r1->end, r2->end); 3450 nearest_ancestor = child; 3451 } 3452 } 3453 } 3454 } 3455 } 3456 return nearest_ancestor; 3457} 3458 3459/* Notify that we're starting to record mergeinfo for the merge of the 3460 * revision range RANGE into TARGET_ABSPATH. RANGE should be null if the 3461 * merge sources are not from the same URL. 3462 * 3463 * This calls the client's notification receiver (as found in the client 3464 * context), with a WC abspath. 3465 */ 3466static void 3467notify_mergeinfo_recording(const char *target_abspath, 3468 const svn_merge_range_t *range, 3469 svn_client_ctx_t *ctx, 3470 apr_pool_t *pool) 3471{ 3472 if (ctx->notify_func2) 3473 { 3474 svn_wc_notify_t *n = svn_wc_create_notify( 3475 target_abspath, svn_wc_notify_merge_record_info_begin, pool); 3476 3477 n->merge_range = range ? svn_merge_range_dup(range, pool) : NULL; 3478 ctx->notify_func2(ctx->notify_baton2, n, pool); 3479 } 3480} 3481 3482/* Notify that we're completing the merge into TARGET_ABSPATH. 3483 * 3484 * This calls the client's notification receiver (as found in the client 3485 * context), with a WC abspath. 3486 */ 3487static void 3488notify_merge_completed(const char *target_abspath, 3489 svn_client_ctx_t *ctx, 3490 apr_pool_t *pool) 3491{ 3492 if (ctx->notify_func2) 3493 { 3494 svn_wc_notify_t *n 3495 = svn_wc_create_notify(target_abspath, svn_wc_notify_merge_completed, 3496 pool); 3497 ctx->notify_func2(ctx->notify_baton2, n, pool); 3498 } 3499} 3500 3501/* Is the notification the result of a real operative merge? */ 3502#define IS_OPERATIVE_NOTIFICATION(notify) \ 3503 (notify->content_state == svn_wc_notify_state_conflicted \ 3504 || notify->content_state == svn_wc_notify_state_merged \ 3505 || notify->content_state == svn_wc_notify_state_changed \ 3506 || notify->prop_state == svn_wc_notify_state_conflicted \ 3507 || notify->prop_state == svn_wc_notify_state_merged \ 3508 || notify->prop_state == svn_wc_notify_state_changed \ 3509 || notify->action == svn_wc_notify_update_add \ 3510 || notify->action == svn_wc_notify_tree_conflict) 3511 3512 3513/* Remove merge source gaps from range used for merge notifications. 3514 See http://subversion.tigris.org/issues/show_bug.cgi?id=4138 3515 3516 If IMPLICIT_SRC_GAP is not NULL then it is a rangelist containing a 3517 single range (see the implicit_src_gap member of merge_cmd_baton_t). 3518 RANGE describes a (possibly reverse) merge. 3519 3520 If IMPLICIT_SRC_GAP is not NULL and it's sole range intersects with 3521 the older revision in *RANGE, then remove IMPLICIT_SRC_GAP's range 3522 from *RANGE. */ 3523static void 3524remove_source_gap(svn_merge_range_t *range, 3525 apr_array_header_t *implicit_src_gap) 3526{ 3527 if (implicit_src_gap) 3528 { 3529 svn_merge_range_t *gap_range = 3530 APR_ARRAY_IDX(implicit_src_gap, 0, svn_merge_range_t *); 3531 if (range->start < range->end) 3532 { 3533 if (gap_range->start == range->start) 3534 range->start = gap_range->end; 3535 } 3536 else /* Reverse merge */ 3537 { 3538 if (gap_range->start == range->end) 3539 range->end = gap_range->end; 3540 } 3541 } 3542} 3543 3544/* Notify that we're starting a merge 3545 * 3546 * This calls the client's notification receiver (as found in the client 3547 * context), with a WC abspath. 3548 */ 3549static svn_error_t * 3550notify_merge_begin(merge_cmd_baton_t *merge_b, 3551 const char *local_abspath, 3552 svn_boolean_t delete_action, 3553 apr_pool_t *scratch_pool) 3554{ 3555 svn_wc_notify_t *notify; 3556 svn_merge_range_t n_range = 3557 {SVN_INVALID_REVNUM, SVN_INVALID_REVNUM, TRUE}; 3558 const char *notify_abspath; 3559 3560 if (! merge_b->ctx->notify_func2) 3561 return SVN_NO_ERROR; 3562 3563 /* If our merge sources are ancestors of one another... */ 3564 if (merge_b->merge_source.ancestral) 3565 { 3566 const svn_client__merge_path_t *child; 3567 /* Find NOTIFY->PATH's nearest ancestor in 3568 NOTIFY->CHILDREN_WITH_MERGEINFO. Normally we consider a child in 3569 NOTIFY->CHILDREN_WITH_MERGEINFO representing PATH to be an 3570 ancestor of PATH, but if this is a deletion of PATH then the 3571 notification must be for a proper ancestor of PATH. This ensures 3572 we don't get notifications like: 3573 3574 --- Merging rX into 'PARENT/CHILD' 3575 D PARENT/CHILD 3576 3577 But rather: 3578 3579 --- Merging rX into 'PARENT' 3580 D PARENT/CHILD 3581 */ 3582 3583 child = find_nearest_ancestor_with_intersecting_ranges( 3584 &(n_range.start), &(n_range.end), 3585 merge_b->notify_begin.nodes_with_mergeinfo, 3586 ! delete_action, local_abspath); 3587 3588 if (!child && delete_action) 3589 { 3590 /* Triggered by file replace in single-file-merge */ 3591 child = find_nearest_ancestor(merge_b->notify_begin.nodes_with_mergeinfo, 3592 TRUE, local_abspath); 3593 } 3594 3595 assert(child != NULL); /* Should always find the merge anchor */ 3596 3597 if (! child) 3598 return SVN_NO_ERROR; 3599 3600 if (merge_b->notify_begin.last_abspath != NULL 3601 && strcmp(child->abspath, merge_b->notify_begin.last_abspath) == 0) 3602 { 3603 /* Don't notify the same merge again */ 3604 return SVN_NO_ERROR; 3605 } 3606 3607 merge_b->notify_begin.last_abspath = child->abspath; 3608 3609 if (child->absent || child->remaining_ranges->nelts == 0 3610 || !SVN_IS_VALID_REVNUM(n_range.start)) 3611 { 3612 /* No valid information for an header */ 3613 return SVN_NO_ERROR; 3614 } 3615 3616 notify_abspath = child->abspath; 3617 } 3618 else 3619 { 3620 if (merge_b->notify_begin.last_abspath) 3621 return SVN_NO_ERROR; /* already notified */ 3622 3623 notify_abspath = merge_b->target->abspath; 3624 /* Store something in last_abspath. Any value would do */ 3625 merge_b->notify_begin.last_abspath = merge_b->target->abspath; 3626 } 3627 3628 notify = svn_wc_create_notify(notify_abspath, 3629 merge_b->same_repos 3630 ? svn_wc_notify_merge_begin 3631 : svn_wc_notify_foreign_merge_begin, 3632 scratch_pool); 3633 3634 if (SVN_IS_VALID_REVNUM(n_range.start)) 3635 { 3636 /* If the merge source has a gap, then don't mention 3637 those gap revisions in the notification. */ 3638 remove_source_gap(&n_range, merge_b->implicit_src_gap); 3639 notify->merge_range = &n_range; 3640 } 3641 else 3642 { 3643 notify->merge_range = NULL; 3644 } 3645 3646 (*merge_b->ctx->notify_func2)(merge_b->ctx->notify_baton2, notify, 3647 scratch_pool); 3648 3649 return SVN_NO_ERROR; 3650} 3651 3652/* Set *OUT_RANGELIST to the intersection of IN_RANGELIST with the simple 3653 * (inheritable) revision range REV1:REV2, according to CONSIDER_INHERITANCE. 3654 * If REV1 is equal to REV2, the result is an empty rangelist, otherwise 3655 * REV1 must be less than REV2. 3656 * 3657 * Note: If CONSIDER_INHERITANCE is FALSE, the effect is to treat any non- 3658 * inheritable input ranges as if they were inheritable. If it is TRUE, the 3659 * effect is to discard any non-inheritable input ranges. Therefore the 3660 * ranges in *OUT_RANGELIST will always be inheritable. */ 3661static svn_error_t * 3662rangelist_intersect_range(svn_rangelist_t **out_rangelist, 3663 const svn_rangelist_t *in_rangelist, 3664 svn_revnum_t rev1, 3665 svn_revnum_t rev2, 3666 svn_boolean_t consider_inheritance, 3667 apr_pool_t *result_pool, 3668 apr_pool_t *scratch_pool) 3669{ 3670 SVN_ERR_ASSERT(rev1 <= rev2); 3671 3672 if (rev1 < rev2) 3673 { 3674 svn_rangelist_t *simple_rangelist = 3675 svn_rangelist__initialize(rev1, rev2, TRUE, scratch_pool); 3676 3677 SVN_ERR(svn_rangelist_intersect(out_rangelist, 3678 simple_rangelist, in_rangelist, 3679 consider_inheritance, result_pool)); 3680 } 3681 else 3682 { 3683 *out_rangelist = apr_array_make(result_pool, 0, 3684 sizeof(svn_merge_range_t *)); 3685 } 3686 return SVN_NO_ERROR; 3687} 3688 3689/* Helper for fix_deleted_subtree_ranges(). Like fix_deleted_subtree_ranges() 3690 this function should only be called when honoring mergeinfo. 3691 3692 CHILD, PARENT, REVISION1, REVISION2, and RA_SESSION are all cascaded from 3693 fix_deleted_subtree_ranges() -- see that function for more information on 3694 each. 3695 3696 If PARENT is not the merge target then PARENT must have already have been 3697 processed by this function as a child. Specifically, this means that 3698 PARENT->REMAINING_RANGES must already be populated -- it can be an empty 3699 rangelist but cannot be NULL. 3700 3701 PRIMARY_URL is the merge source url of CHILD at the younger of REVISION1 3702 and REVISION2. 3703 3704 Since this function is only invoked for subtrees of the merge target, the 3705 guarantees afforded by normalize_merge_sources() don't apply - see the 3706 'MERGEINFO MERGE SOURCE NORMALIZATION' comment at the top of this file. 3707 Therefore it is possible that PRIMARY_URL@REVISION1 and 3708 PRIMARY_URL@REVISION2 don't describe the endpoints of an unbroken line of 3709 history. The purpose of this helper is to identify these cases of broken 3710 history and adjust CHILD->REMAINING_RANGES in such a way we don't later try 3711 to describe nonexistent path/revisions to the merge report editor -- see 3712 drive_merge_report_editor(). 3713 3714 If PRIMARY_URL@REVISION1 and PRIMARY_URL@REVISION2 describe an unbroken 3715 line of history then do nothing and leave CHILD->REMAINING_RANGES as-is. 3716 3717 If neither PRIMARY_URL@REVISION1 nor PRIMARY_URL@REVISION2 exist then 3718 there is nothing to merge to CHILD->ABSPATH so set CHILD->REMAINING_RANGES 3719 equal to PARENT->REMAINING_RANGES. This will cause the subtree to 3720 effectively ignore CHILD -- see 'Note: If the first svn_merge_range_t...' 3721 in drive_merge_report_editor()'s doc string. 3722 3723 If PRIMARY_URL@REVISION1 *xor* PRIMARY_URL@REVISION2 exist then we take the 3724 subset of REVISION1:REVISION2 in CHILD->REMAINING_RANGES at which 3725 PRIMARY_URL doesn't exist and set that subset equal to 3726 PARENT->REMAINING_RANGES' intersection with that non-existent range. Why? 3727 Because this causes CHILD->REMAINING_RANGES to be identical to 3728 PARENT->REMAINING_RANGES for revisions between REVISION1 and REVISION2 at 3729 which PRIMARY_URL doesn't exist. As mentioned above this means that 3730 drive_merge_report_editor() won't attempt to describe these non-existent 3731 subtree path/ranges to the reporter (which would break the merge). 3732 3733 If the preceding paragraph wasn't terribly clear then what follows spells 3734 out this function's behavior a bit more explicitly: 3735 3736 For forward merges (REVISION1 < REVISION2) 3737 3738 If PRIMARY_URL@REVISION1 exists but PRIMARY_URL@REVISION2 doesn't, then 3739 find the revision 'N' in which PRIMARY_URL@REVISION1 was deleted. Leave 3740 the subset of CHILD->REMAINING_RANGES that intersects with 3741 REVISION1:(N - 1) as-is and set the subset of CHILD->REMAINING_RANGES 3742 that intersects with (N - 1):REVISION2 equal to PARENT->REMAINING_RANGES' 3743 intersection with (N - 1):REVISION2. 3744 3745 If PRIMARY_URL@REVISION1 doesn't exist but PRIMARY_URL@REVISION2 does, 3746 then find the revision 'M' in which PRIMARY_URL@REVISION2 came into 3747 existence. Leave the subset of CHILD->REMAINING_RANGES that intersects with 3748 (M - 1):REVISION2 as-is and set the subset of CHILD->REMAINING_RANGES 3749 that intersects with REVISION1:(M - 1) equal to PARENT->REMAINING_RANGES' 3750 intersection with REVISION1:(M - 1). 3751 3752 For reverse merges (REVISION1 > REVISION2) 3753 3754 If PRIMARY_URL@REVISION1 exists but PRIMARY_URL@REVISION2 doesn't, then 3755 find the revision 'N' in which PRIMARY_URL@REVISION1 came into existence. 3756 Leave the subset of CHILD->REMAINING_RANGES that intersects with 3757 REVISION2:(N - 1) as-is and set the subset of CHILD->REMAINING_RANGES 3758 that intersects with (N - 1):REVISION1 equal to PARENT->REMAINING_RANGES' 3759 intersection with (N - 1):REVISION1. 3760 3761 If PRIMARY_URL@REVISION1 doesn't exist but PRIMARY_URL@REVISION2 does, 3762 then find the revision 'M' in which PRIMARY_URL@REVISION2 came into 3763 existence. Leave the subset of CHILD->REMAINING_RANGES that intersects with 3764 REVISION2:(M - 1) as-is and set the subset of CHILD->REMAINING_RANGES 3765 that intersects with (M - 1):REVISION1 equal to PARENT->REMAINING_RANGES' 3766 intersection with REVISION1:(M - 1). 3767 3768 SCRATCH_POOL is used for all temporary allocations. Changes to CHILD are 3769 allocated in RESULT_POOL. */ 3770static svn_error_t * 3771adjust_deleted_subtree_ranges(svn_client__merge_path_t *child, 3772 svn_client__merge_path_t *parent, 3773 svn_revnum_t revision1, 3774 svn_revnum_t revision2, 3775 const char *primary_url, 3776 svn_ra_session_t *ra_session, 3777 svn_client_ctx_t *ctx, 3778 apr_pool_t *result_pool, 3779 apr_pool_t *scratch_pool) 3780{ 3781 svn_boolean_t is_rollback = revision2 < revision1; 3782 svn_revnum_t younger_rev = is_rollback ? revision1 : revision2; 3783 svn_revnum_t peg_rev = younger_rev; 3784 svn_revnum_t older_rev = is_rollback ? revision2 : revision1; 3785 apr_array_header_t *segments; 3786 svn_error_t *err; 3787 3788 SVN_ERR_ASSERT(parent->remaining_ranges); 3789 3790 err = svn_client__repos_location_segments(&segments, ra_session, 3791 primary_url, peg_rev, 3792 younger_rev, older_rev, ctx, 3793 scratch_pool); 3794 3795 /* If PRIMARY_URL@peg_rev doesn't exist then 3796 svn_client__repos_location_segments() typically returns an 3797 SVN_ERR_FS_NOT_FOUND error, but if it doesn't exist for a 3798 forward merge over ra_neon then we get SVN_ERR_RA_DAV_REQUEST_FAILED. 3799 http://subversion.tigris.org/issues/show_bug.cgi?id=3137 fixed some of 3800 the cases where different RA layers returned different error codes to 3801 signal the "path not found"...but it looks like there is more to do. 3802 3803 ### Do we still need to special case for ra_neon (since it no longer 3804 exists)? */ 3805 if (err) 3806 { 3807 if (err->apr_err == SVN_ERR_FS_NOT_FOUND 3808 || err->apr_err == SVN_ERR_RA_DAV_REQUEST_FAILED) 3809 { 3810 /* PRIMARY_URL@peg_rev doesn't exist. Check if PRIMARY_URL@older_rev 3811 exists, if neither exist then the editor can simply ignore this 3812 subtree. */ 3813 const char *rel_source_path; /* PRIMARY_URL relative to RA_SESSION */ 3814 svn_node_kind_t kind; 3815 3816 svn_error_clear(err); 3817 err = NULL; 3818 3819 SVN_ERR(svn_ra_get_path_relative_to_session( 3820 ra_session, &rel_source_path, primary_url, scratch_pool)); 3821 3822 SVN_ERR(svn_ra_check_path(ra_session, rel_source_path, 3823 older_rev, &kind, scratch_pool)); 3824 if (kind == svn_node_none) 3825 { 3826 /* Neither PRIMARY_URL@peg_rev nor PRIMARY_URL@older_rev exist, 3827 so there is nothing to merge. Set CHILD->REMAINING_RANGES 3828 identical to PARENT's. */ 3829 child->remaining_ranges = 3830 svn_rangelist_dup(parent->remaining_ranges, scratch_pool); 3831 } 3832 else 3833 { 3834 svn_rangelist_t *deleted_rangelist; 3835 svn_revnum_t rev_primary_url_deleted; 3836 3837 /* PRIMARY_URL@older_rev exists, so it was deleted at some 3838 revision prior to peg_rev, find that revision. */ 3839 SVN_ERR(svn_ra_get_deleted_rev(ra_session, rel_source_path, 3840 older_rev, younger_rev, 3841 &rev_primary_url_deleted, 3842 scratch_pool)); 3843 3844 /* PRIMARY_URL@older_rev exists and PRIMARY_URL@peg_rev doesn't, 3845 so svn_ra_get_deleted_rev() should always find the revision 3846 PRIMARY_URL@older_rev was deleted. */ 3847 SVN_ERR_ASSERT(SVN_IS_VALID_REVNUM(rev_primary_url_deleted)); 3848 3849 /* If this is a reverse merge reorder CHILD->REMAINING_RANGES and 3850 PARENT->REMAINING_RANGES so both will work with the 3851 svn_rangelist_* APIs below. */ 3852 if (is_rollback) 3853 { 3854 /* svn_rangelist_reverse operates in place so it's safe 3855 to use our scratch_pool. */ 3856 SVN_ERR(svn_rangelist_reverse(child->remaining_ranges, 3857 scratch_pool)); 3858 SVN_ERR(svn_rangelist_reverse(parent->remaining_ranges, 3859 scratch_pool)); 3860 } 3861 3862 /* Find the intersection of CHILD->REMAINING_RANGES with the 3863 range over which PRIMARY_URL@older_rev exists (ending at 3864 the youngest revision at which it still exists). */ 3865 SVN_ERR(rangelist_intersect_range(&child->remaining_ranges, 3866 child->remaining_ranges, 3867 older_rev, 3868 rev_primary_url_deleted - 1, 3869 FALSE, 3870 scratch_pool, scratch_pool)); 3871 3872 /* Merge into CHILD->REMAINING_RANGES the intersection of 3873 PARENT->REMAINING_RANGES with the range beginning when 3874 PRIMARY_URL@older_rev was deleted until younger_rev. */ 3875 SVN_ERR(rangelist_intersect_range(&deleted_rangelist, 3876 parent->remaining_ranges, 3877 rev_primary_url_deleted - 1, 3878 peg_rev, 3879 FALSE, 3880 scratch_pool, scratch_pool)); 3881 SVN_ERR(svn_rangelist_merge2(child->remaining_ranges, 3882 deleted_rangelist, scratch_pool, 3883 scratch_pool)); 3884 3885 /* Return CHILD->REMAINING_RANGES and PARENT->REMAINING_RANGES 3886 to reverse order if necessary. */ 3887 if (is_rollback) 3888 { 3889 SVN_ERR(svn_rangelist_reverse(child->remaining_ranges, 3890 scratch_pool)); 3891 SVN_ERR(svn_rangelist_reverse(parent->remaining_ranges, 3892 scratch_pool)); 3893 } 3894 } 3895 } 3896 else 3897 { 3898 return svn_error_trace(err); 3899 } 3900 } 3901 else /* PRIMARY_URL@peg_rev exists. */ 3902 { 3903 svn_rangelist_t *non_existent_rangelist; 3904 svn_location_segment_t *segment = 3905 APR_ARRAY_IDX(segments, (segments->nelts - 1), 3906 svn_location_segment_t *); 3907 3908 /* We know PRIMARY_URL@peg_rev exists as the call to 3909 svn_client__repos_location_segments() succeeded. If there is only 3910 one segment that starts at oldest_rev then we know that 3911 PRIMARY_URL@oldest_rev:PRIMARY_URL@peg_rev describes an unbroken 3912 line of history, so there is nothing more to adjust in 3913 CHILD->REMAINING_RANGES. */ 3914 if (segment->range_start == older_rev) 3915 { 3916 return SVN_NO_ERROR; 3917 } 3918 3919 /* If this is a reverse merge reorder CHILD->REMAINING_RANGES and 3920 PARENT->REMAINING_RANGES so both will work with the 3921 svn_rangelist_* APIs below. */ 3922 if (is_rollback) 3923 { 3924 SVN_ERR(svn_rangelist_reverse(child->remaining_ranges, 3925 scratch_pool)); 3926 SVN_ERR(svn_rangelist_reverse(parent->remaining_ranges, 3927 scratch_pool)); 3928 } 3929 3930 /* Intersect CHILD->REMAINING_RANGES with the range where PRIMARY_URL 3931 exists. Since segment doesn't span older_rev:peg_rev we know 3932 PRIMARY_URL@peg_rev didn't come into existence until 3933 segment->range_start + 1. */ 3934 SVN_ERR(rangelist_intersect_range(&child->remaining_ranges, 3935 child->remaining_ranges, 3936 segment->range_start, peg_rev, 3937 FALSE, scratch_pool, scratch_pool)); 3938 3939 /* Merge into CHILD->REMAINING_RANGES the intersection of 3940 PARENT->REMAINING_RANGES with the range before PRIMARY_URL@peg_rev 3941 came into existence. */ 3942 SVN_ERR(rangelist_intersect_range(&non_existent_rangelist, 3943 parent->remaining_ranges, 3944 older_rev, segment->range_start, 3945 FALSE, scratch_pool, scratch_pool)); 3946 SVN_ERR(svn_rangelist_merge2(child->remaining_ranges, 3947 non_existent_rangelist, scratch_pool, 3948 scratch_pool)); 3949 3950 /* Return CHILD->REMAINING_RANGES and PARENT->REMAINING_RANGES 3951 to reverse order if necessary. */ 3952 if (is_rollback) 3953 { 3954 SVN_ERR(svn_rangelist_reverse(child->remaining_ranges, 3955 scratch_pool)); 3956 SVN_ERR(svn_rangelist_reverse(parent->remaining_ranges, 3957 scratch_pool)); 3958 } 3959 } 3960 3961 /* Make a lasting copy of CHILD->REMAINING_RANGES using POOL. */ 3962 child->remaining_ranges = svn_rangelist_dup(child->remaining_ranges, 3963 result_pool); 3964 return SVN_NO_ERROR; 3965} 3966 3967/* Helper for do_directory_merge(). 3968 3969 SOURCE is cascaded from the argument of the same name in 3970 do_directory_merge(). TARGET is the merge target. RA_SESSION is the 3971 session for the younger of SOURCE->loc1 and SOURCE->loc2. 3972 3973 Adjust the subtrees in CHILDREN_WITH_MERGEINFO so that we don't 3974 later try to describe invalid paths in drive_merge_report_editor(). 3975 This function is just a thin wrapper around 3976 adjust_deleted_subtree_ranges(), which see for further details. 3977 3978 SCRATCH_POOL is used for all temporary allocations. Changes to 3979 CHILDREN_WITH_MERGEINFO are allocated in RESULT_POOL. 3980*/ 3981static svn_error_t * 3982fix_deleted_subtree_ranges(const merge_source_t *source, 3983 const merge_target_t *target, 3984 svn_ra_session_t *ra_session, 3985 apr_array_header_t *children_with_mergeinfo, 3986 svn_client_ctx_t *ctx, 3987 apr_pool_t *result_pool, 3988 apr_pool_t *scratch_pool) 3989{ 3990 int i; 3991 apr_pool_t *iterpool = svn_pool_create(scratch_pool); 3992 svn_boolean_t is_rollback = source->loc2->rev < source->loc1->rev; 3993 3994 assert(session_url_is(ra_session, 3995 (is_rollback ? source->loc1 : source->loc2)->url, 3996 scratch_pool)); 3997 3998 /* CHILDREN_WITH_MERGEINFO is sorted in depth-first order, so 3999 start at index 1 to examine only subtrees. */ 4000 for (i = 1; i < children_with_mergeinfo->nelts; i++) 4001 { 4002 svn_client__merge_path_t *child = 4003 APR_ARRAY_IDX(children_with_mergeinfo, i, svn_client__merge_path_t *); 4004 svn_client__merge_path_t *parent; 4005 svn_rangelist_t *deleted_rangelist, *added_rangelist; 4006 4007 SVN_ERR_ASSERT(child); 4008 if (child->absent) 4009 continue; 4010 4011 svn_pool_clear(iterpool); 4012 4013 /* Find CHILD's parent. */ 4014 parent = find_nearest_ancestor(children_with_mergeinfo, 4015 FALSE, child->abspath); 4016 4017 /* Since CHILD is a subtree then its parent must be in 4018 CHILDREN_WITH_MERGEINFO, see the global comment 4019 'THE CHILDREN_WITH_MERGEINFO ARRAY'. */ 4020 SVN_ERR_ASSERT(parent); 4021 4022 /* If this is a reverse merge reorder CHILD->REMAINING_RANGES 4023 so it will work with the svn_rangelist_diff API. */ 4024 if (is_rollback) 4025 { 4026 SVN_ERR(svn_rangelist_reverse(child->remaining_ranges, iterpool)); 4027 SVN_ERR(svn_rangelist_reverse(parent->remaining_ranges, iterpool)); 4028 } 4029 4030 SVN_ERR(svn_rangelist_diff(&deleted_rangelist, &added_rangelist, 4031 child->remaining_ranges, 4032 parent->remaining_ranges, 4033 TRUE, iterpool)); 4034 4035 if (is_rollback) 4036 { 4037 SVN_ERR(svn_rangelist_reverse(child->remaining_ranges, iterpool)); 4038 SVN_ERR(svn_rangelist_reverse(parent->remaining_ranges, iterpool)); 4039 } 4040 4041 /* If CHILD is the merge target we then know that SOURCE is provided 4042 by normalize_merge_sources() -- see 'MERGEINFO MERGE SOURCE 4043 NORMALIZATION'. Due to this normalization we know that SOURCE 4044 describes an unbroken line of history such that the entire range 4045 described by SOURCE can potentially be merged to CHILD. 4046 4047 But if CHILD is a subtree we don't have the same guarantees about 4048 SOURCE as we do for the merge target. SOURCE->loc1 and/or 4049 SOURCE->loc2 might not exist. 4050 4051 If one or both doesn't exist, then adjust CHILD->REMAINING_RANGES 4052 such that we don't later try to describe invalid subtrees in 4053 drive_merge_report_editor(), as that will break the merge. 4054 If CHILD has the same remaining ranges as PARENT however, then 4055 there is no need to make these adjustments, since 4056 drive_merge_report_editor() won't attempt to describe CHILD in this 4057 case, see the 'Note' in drive_merge_report_editor's docstring. */ 4058 if (deleted_rangelist->nelts || added_rangelist->nelts) 4059 { 4060 const char *child_primary_source_url; 4061 const char *child_repos_src_path = 4062 svn_dirent_is_child(target->abspath, child->abspath, iterpool); 4063 4064 /* This loop is only processing subtrees, so CHILD->ABSPATH 4065 better be a proper child of the merge target. */ 4066 SVN_ERR_ASSERT(child_repos_src_path); 4067 4068 child_primary_source_url = 4069 svn_path_url_add_component2((source->loc1->rev < source->loc2->rev) 4070 ? source->loc2->url : source->loc1->url, 4071 child_repos_src_path, iterpool); 4072 4073 SVN_ERR(adjust_deleted_subtree_ranges(child, parent, 4074 source->loc1->rev, 4075 source->loc2->rev, 4076 child_primary_source_url, 4077 ra_session, 4078 ctx, result_pool, iterpool)); 4079 } 4080 } 4081 4082 svn_pool_destroy(iterpool); 4083 return SVN_NO_ERROR; 4084} 4085 4086/*-----------------------------------------------------------------------*/ 4087 4088/*** Determining What Remains To Be Merged ***/ 4089 4090/* Get explicit and/or implicit mergeinfo for the working copy path 4091 TARGET_ABSPATH. 4092 4093 If RECORDED_MERGEINFO is not NULL then set *RECORDED_MERGEINFO 4094 to TARGET_ABSPATH's explicit or inherited mergeinfo as dictated by 4095 INHERIT. 4096 4097 If IMPLICIT_MERGEINFO is not NULL then set *IMPLICIT_MERGEINFO 4098 to TARGET_ABSPATH's implicit mergeinfo (a.k.a. natural history). 4099 4100 If both RECORDED_MERGEINFO and IMPLICIT_MERGEINFO are not NULL and 4101 *RECORDED_MERGEINFO is inherited, then *IMPLICIT_MERGEINFO will be 4102 removed from *RECORDED_MERGEINFO. 4103 4104 If INHERITED is not NULL set *INHERITED to TRUE if *RECORDED_MERGEINFO 4105 is inherited rather than explicit. If RECORDED_MERGEINFO is NULL then 4106 INHERITED is ignored. 4107 4108 4109 If IMPLICIT_MERGEINFO is not NULL then START and END are limits on 4110 the natural history sought, must both be valid revision numbers, and 4111 START must be greater than END. If TARGET_ABSPATH's base revision 4112 is older than START, then the base revision is used as the younger 4113 bound in place of START. 4114 4115 RA_SESSION is an RA session open to the repository in which TARGET_ABSPATH 4116 lives. It may be temporarily reparented as needed by this function. 4117 4118 Allocate *RECORDED_MERGEINFO and *IMPLICIT_MERGEINFO in RESULT_POOL. 4119 Use SCRATCH_POOL for any temporary allocations. */ 4120static svn_error_t * 4121get_full_mergeinfo(svn_mergeinfo_t *recorded_mergeinfo, 4122 svn_mergeinfo_t *implicit_mergeinfo, 4123 svn_boolean_t *inherited, 4124 svn_mergeinfo_inheritance_t inherit, 4125 svn_ra_session_t *ra_session, 4126 const char *target_abspath, 4127 svn_revnum_t start, 4128 svn_revnum_t end, 4129 svn_client_ctx_t *ctx, 4130 apr_pool_t *result_pool, 4131 apr_pool_t *scratch_pool) 4132{ 4133 /* First, we get the real mergeinfo. */ 4134 if (recorded_mergeinfo) 4135 { 4136 SVN_ERR(svn_client__get_wc_or_repos_mergeinfo(recorded_mergeinfo, 4137 inherited, 4138 NULL /* from_repos */, 4139 FALSE, 4140 inherit, ra_session, 4141 target_abspath, 4142 ctx, result_pool)); 4143 } 4144 4145 if (implicit_mergeinfo) 4146 { 4147 svn_client__pathrev_t *target; 4148 4149 /* Assert that we have sane input. */ 4150 SVN_ERR_ASSERT(SVN_IS_VALID_REVNUM(start) && SVN_IS_VALID_REVNUM(end) 4151 && (start > end)); 4152 4153 /* Retrieve the origin (original_*) of the node, or just the 4154 url if the node was not copied. */ 4155 SVN_ERR(svn_client__wc_node_get_origin(&target, target_abspath, ctx, 4156 scratch_pool, scratch_pool)); 4157 4158 if (! target) 4159 { 4160 /* We've been asked to operate on a locally added target, so its 4161 * implicit mergeinfo is empty. */ 4162 *implicit_mergeinfo = apr_hash_make(result_pool); 4163 } 4164 else if (target->rev <= end) 4165 { 4166 /* We're asking about a range outside our natural history 4167 altogether. That means our implicit mergeinfo is empty. */ 4168 *implicit_mergeinfo = apr_hash_make(result_pool); 4169 } 4170 else 4171 { 4172 /* Fetch so-called "implicit mergeinfo" (that is, natural 4173 history). */ 4174 4175 /* Do not ask for implicit mergeinfo from TARGET_ABSPATH's future. 4176 TARGET_ABSPATH might not even exist, and even if it does the 4177 working copy is *at* TARGET_REV so its implicit history ends 4178 at TARGET_REV! */ 4179 if (target->rev < start) 4180 start = target->rev; 4181 4182 /* Fetch the implicit mergeinfo. */ 4183 SVN_ERR(svn_client__get_history_as_mergeinfo(implicit_mergeinfo, 4184 NULL, 4185 target, start, end, 4186 ra_session, ctx, 4187 result_pool)); 4188 } 4189 } /*if (implicit_mergeinfo) */ 4190 4191 return SVN_NO_ERROR; 4192} 4193 4194/* Helper for ensure_implicit_mergeinfo(). 4195 4196 PARENT, CHILD, REVISION1, REVISION2 and CTX 4197 are all cascaded from the arguments of the same names in 4198 ensure_implicit_mergeinfo(). PARENT and CHILD must both exist, i.e. 4199 this function should never be called where CHILD is the merge target. 4200 4201 If PARENT->IMPLICIT_MERGEINFO is NULL, obtain it from the server. 4202 4203 Set CHILD->IMPLICIT_MERGEINFO to the mergeinfo inherited from 4204 PARENT->IMPLICIT_MERGEINFO. CHILD->IMPLICIT_MERGEINFO is allocated 4205 in RESULT_POOL. 4206 4207 RA_SESSION is an RA session open to the repository that contains CHILD. 4208 It may be temporarily reparented by this function. 4209 */ 4210static svn_error_t * 4211inherit_implicit_mergeinfo_from_parent(svn_client__merge_path_t *parent, 4212 svn_client__merge_path_t *child, 4213 svn_revnum_t revision1, 4214 svn_revnum_t revision2, 4215 svn_ra_session_t *ra_session, 4216 svn_client_ctx_t *ctx, 4217 apr_pool_t *result_pool, 4218 apr_pool_t *scratch_pool) 4219{ 4220 const char *path_diff; 4221 4222 /* This only works on subtrees! */ 4223 SVN_ERR_ASSERT(parent); 4224 SVN_ERR_ASSERT(child); 4225 4226 /* While PARENT must exist, it is possible we've deferred 4227 getting its implicit mergeinfo. If so get it now. */ 4228 if (!parent->implicit_mergeinfo) 4229 SVN_ERR(get_full_mergeinfo(NULL, &(parent->implicit_mergeinfo), 4230 NULL, svn_mergeinfo_inherited, 4231 ra_session, child->abspath, 4232 MAX(revision1, revision2), 4233 MIN(revision1, revision2), 4234 ctx, result_pool, scratch_pool)); 4235 4236 /* Let CHILD inherit PARENT's implicit mergeinfo. */ 4237 4238 path_diff = svn_dirent_is_child(parent->abspath, child->abspath, 4239 scratch_pool); 4240 /* PARENT->PATH better be an ancestor of CHILD->ABSPATH! */ 4241 SVN_ERR_ASSERT(path_diff); 4242 4243 SVN_ERR(svn_mergeinfo__add_suffix_to_mergeinfo( 4244 &child->implicit_mergeinfo, parent->implicit_mergeinfo, 4245 path_diff, result_pool, scratch_pool)); 4246 child->implicit_mergeinfo = svn_mergeinfo_dup(child->implicit_mergeinfo, 4247 result_pool); 4248 return SVN_NO_ERROR; 4249} 4250 4251/* Helper of filter_merged_revisions(). 4252 4253 If we have deferred obtaining CHILD->IMPLICIT_MERGEINFO, then get 4254 it now, allocating it in RESULT_POOL. If CHILD_INHERITS_PARENT is true 4255 then set CHILD->IMPLICIT_MERGEINFO to the mergeinfo inherited from 4256 PARENT->IMPLICIT_MERGEINFO, otherwise contact the repository. Use 4257 SCRATCH_POOL for all temporary allocations. 4258 4259 RA_SESSION is an RA session open to the repository that contains CHILD. 4260 It may be temporarily reparented by this function. 4261 4262 PARENT, CHILD, REVISION1, REVISION2 and 4263 CTX are all cascaded from the arguments of the same name in 4264 filter_merged_revisions() and the same conditions for that function 4265 hold here. */ 4266static svn_error_t * 4267ensure_implicit_mergeinfo(svn_client__merge_path_t *parent, 4268 svn_client__merge_path_t *child, 4269 svn_boolean_t child_inherits_parent, 4270 svn_revnum_t revision1, 4271 svn_revnum_t revision2, 4272 svn_ra_session_t *ra_session, 4273 svn_client_ctx_t *ctx, 4274 apr_pool_t *result_pool, 4275 apr_pool_t *scratch_pool) 4276{ 4277 /* If we haven't already found CHILD->IMPLICIT_MERGEINFO then 4278 contact the server to get it. */ 4279 4280 if (child->implicit_mergeinfo) 4281 return SVN_NO_ERROR; 4282 4283 if (child_inherits_parent) 4284 SVN_ERR(inherit_implicit_mergeinfo_from_parent(parent, 4285 child, 4286 revision1, 4287 revision2, 4288 ra_session, 4289 ctx, 4290 result_pool, 4291 scratch_pool)); 4292 else 4293 SVN_ERR(get_full_mergeinfo(NULL, 4294 &(child->implicit_mergeinfo), 4295 NULL, svn_mergeinfo_inherited, 4296 ra_session, child->abspath, 4297 MAX(revision1, revision2), 4298 MIN(revision1, revision2), 4299 ctx, result_pool, scratch_pool)); 4300 4301 return SVN_NO_ERROR; 4302} 4303 4304/* Helper for calculate_remaining_ranges(). 4305 4306 Initialize CHILD->REMAINING_RANGES to a rangelist representing the 4307 requested merge of REVISION1:REVISION2 from MERGEINFO_PATH to 4308 CHILD->ABSPATH. 4309 4310 For forward merges remove any ranges from CHILD->REMAINING_RANGES that 4311 have already been merged to CHILD->ABSPATH per TARGET_MERGEINFO or 4312 CHILD->IMPLICIT_MERGEINFO. For reverse merges remove any ranges from 4313 CHILD->REMAINING_RANGES that have not already been merged to CHILD->ABSPATH 4314 per TARGET_MERGEINFO or CHILD->IMPLICIT_MERGEINFO. If we have deferred 4315 obtaining CHILD->IMPLICIT_MERGEINFO and it is necessary to use it for 4316 these calculations, then get it from the server, allocating it in 4317 RESULT_POOL. 4318 4319 CHILD represents a working copy path which is the merge target or one of 4320 the target's subtrees. If not NULL, PARENT is CHILD's nearest path-wise 4321 ancestor - see 'THE CHILDREN_WITH_MERGEINFO ARRAY'. 4322 4323 If the function needs to consider CHILD->IMPLICIT_MERGEINFO and 4324 CHILD_INHERITS_IMPLICIT is true, then set CHILD->IMPLICIT_MERGEINFO to the 4325 mergeinfo inherited from PARENT->IMPLICIT_MERGEINFO. Otherwise contact 4326 the repository for CHILD->IMPLICIT_MERGEINFO. 4327 4328 NOTE: If PARENT is present then this function must have previously been 4329 called for PARENT, i.e. if populate_remaining_ranges() is calling this 4330 function for a set of svn_client__merge_path_t* the calls must be made 4331 in depth-first order. 4332 4333 MERGEINFO_PATH is the merge source relative to the repository root. 4334 4335 REVISION1 and REVISION2 describe the merge range requested from 4336 MERGEINFO_PATH. 4337 4338 TARGET_RANGELIST is the portion of CHILD->ABSPATH's explicit or inherited 4339 mergeinfo that intersects with the merge history described by 4340 MERGEINFO_PATH@REVISION1:MERGEINFO_PATH@REVISION2. TARGET_RANGELIST 4341 should be NULL if there is no explicit or inherited mergeinfo on 4342 CHILD->ABSPATH or an empty list if CHILD->ABSPATH has empty mergeinfo or 4343 explicit mergeinfo that exclusively describes non-intersecting history 4344 with MERGEINFO_PATH@REVISION1:MERGEINFO_PATH@REVISION2. 4345 4346 SCRATCH_POOL is used for all temporary allocations. 4347 4348 NOTE: This should only be called when honoring mergeinfo. 4349 4350 NOTE: Like calculate_remaining_ranges() if PARENT is present then this 4351 function must have previously been called for PARENT. 4352*/ 4353static svn_error_t * 4354filter_merged_revisions(svn_client__merge_path_t *parent, 4355 svn_client__merge_path_t *child, 4356 const char *mergeinfo_path, 4357 svn_rangelist_t *target_rangelist, 4358 svn_revnum_t revision1, 4359 svn_revnum_t revision2, 4360 svn_boolean_t child_inherits_implicit, 4361 svn_ra_session_t *ra_session, 4362 svn_client_ctx_t *ctx, 4363 apr_pool_t *result_pool, 4364 apr_pool_t *scratch_pool) 4365{ 4366 svn_rangelist_t *requested_rangelist, 4367 *target_implicit_rangelist, *explicit_rangelist; 4368 4369 /* Convert REVISION1 and REVISION2 to a rangelist. 4370 4371 Note: Talking about a requested merge range's inheritability 4372 doesn't make much sense, but as we are using svn_merge_range_t 4373 to describe it we need to pick *something*. Since all the 4374 rangelist manipulations in this function either don't consider 4375 inheritance by default or we are requesting that they don't (i.e. 4376 svn_rangelist_remove and svn_rangelist_intersect) then we could 4377 set the inheritability as FALSE, it won't matter either way. */ 4378 requested_rangelist = svn_rangelist__initialize(revision1, revision2, 4379 TRUE, scratch_pool); 4380 4381 /* Now filter out revisions that have already been merged to CHILD. */ 4382 4383 if (revision1 > revision2) /* This is a reverse merge. */ 4384 { 4385 svn_rangelist_t *added_rangelist, *deleted_rangelist; 4386 4387 /* The revert range and will need to be reversed for 4388 our svn_rangelist_* APIs to work properly. */ 4389 SVN_ERR(svn_rangelist_reverse(requested_rangelist, scratch_pool)); 4390 4391 /* Set EXPLICIT_RANGELIST to the list of source-range revs that are 4392 already recorded as merged to target. */ 4393 if (target_rangelist) 4394 { 4395 /* Return the intersection of the revs which are both already 4396 represented by CHILD's explicit or inherited mergeinfo. 4397 4398 We don't consider inheritance when determining intersecting 4399 ranges. If we *did* consider inheritance, then our calculation 4400 would be wrong. For example, if the CHILD->REMAINING_RANGES is 4401 5:3 and TARGET_RANGELIST is r5* (non-inheritable) then the 4402 intersection would be r4. And that would be wrong as we clearly 4403 want to reverse merge both r4 and r5 in this case. Ignoring the 4404 ranges' inheritance results in an intersection of r4-5. 4405 4406 You might be wondering about CHILD's children, doesn't the above 4407 imply that we will reverse merge r4-5 from them? Nope, this is 4408 safe to do because any path whose parent has non-inheritable 4409 ranges is always considered a subtree with differing mergeinfo 4410 even if that path has no explicit mergeinfo prior to the 4411 merge -- See condition 3 in the doc string for 4412 merge.c:get_mergeinfo_paths(). */ 4413 SVN_ERR(svn_rangelist_intersect(&explicit_rangelist, 4414 target_rangelist, 4415 requested_rangelist, 4416 FALSE, scratch_pool)); 4417 } 4418 else 4419 { 4420 explicit_rangelist = 4421 apr_array_make(result_pool, 0, sizeof(svn_merge_range_t *)); 4422 } 4423 4424 /* Was any part of the requested reverse merge not accounted for in 4425 CHILD's explicit or inherited mergeinfo? */ 4426 SVN_ERR(svn_rangelist_diff(&deleted_rangelist, &added_rangelist, 4427 requested_rangelist, explicit_rangelist, 4428 FALSE, scratch_pool)); 4429 4430 if (deleted_rangelist->nelts == 0) 4431 { 4432 /* The whole of REVISION1:REVISION2 was represented in CHILD's 4433 explicit/inherited mergeinfo, allocate CHILD's remaining 4434 ranges in POOL and then we are done. */ 4435 SVN_ERR(svn_rangelist_reverse(requested_rangelist, scratch_pool)); 4436 child->remaining_ranges = svn_rangelist_dup(requested_rangelist, 4437 result_pool); 4438 } 4439 else /* We need to check CHILD's implicit mergeinfo. */ 4440 { 4441 svn_rangelist_t *implicit_rangelist; 4442 4443 SVN_ERR(ensure_implicit_mergeinfo(parent, 4444 child, 4445 child_inherits_implicit, 4446 revision1, 4447 revision2, 4448 ra_session, 4449 ctx, 4450 result_pool, 4451 scratch_pool)); 4452 4453 target_implicit_rangelist = svn_hash_gets(child->implicit_mergeinfo, 4454 mergeinfo_path); 4455 4456 if (target_implicit_rangelist) 4457 SVN_ERR(svn_rangelist_intersect(&implicit_rangelist, 4458 target_implicit_rangelist, 4459 requested_rangelist, 4460 FALSE, scratch_pool)); 4461 else 4462 implicit_rangelist = apr_array_make(scratch_pool, 0, 4463 sizeof(svn_merge_range_t *)); 4464 4465 SVN_ERR(svn_rangelist_merge2(implicit_rangelist, 4466 explicit_rangelist, scratch_pool, 4467 scratch_pool)); 4468 SVN_ERR(svn_rangelist_reverse(implicit_rangelist, scratch_pool)); 4469 child->remaining_ranges = svn_rangelist_dup(implicit_rangelist, 4470 result_pool); 4471 } 4472 } 4473 else /* This is a forward merge */ 4474 { 4475 /* Set EXPLICIT_RANGELIST to the list of source-range revs that are 4476 NOT already recorded as merged to target. */ 4477 if (target_rangelist) 4478 { 4479 /* See earlier comment preceding svn_rangelist_intersect() for 4480 why we don't consider inheritance here. */ 4481 SVN_ERR(svn_rangelist_remove(&explicit_rangelist, 4482 target_rangelist, 4483 requested_rangelist, FALSE, 4484 scratch_pool)); 4485 } 4486 else 4487 { 4488 explicit_rangelist = svn_rangelist_dup(requested_rangelist, 4489 scratch_pool); 4490 } 4491 4492 if (explicit_rangelist->nelts == 0) 4493 { 4494 child->remaining_ranges = 4495 apr_array_make(result_pool, 0, sizeof(svn_merge_range_t *)); 4496 } 4497 else 4498/* ### TODO: Which evil shall we choose? 4499 ### 4500 ### If we allow all forward-merges not already found in recorded 4501 ### mergeinfo, we destroy the ability to, say, merge the whole of a 4502 ### branch to the trunk while automatically ignoring the revisions 4503 ### common to both. That's bad. 4504 ### 4505 ### If we allow only forward-merges not found in either recorded 4506 ### mergeinfo or implicit mergeinfo (natural history), then the 4507 ### previous scenario works great, but we can't reverse-merge a 4508 ### previous change made to our line of history and then remake it 4509 ### (because the reverse-merge will leave no mergeinfo trace, and 4510 ### the remake-it attempt will still find the original change in 4511 ### natural mergeinfo. But you know, that we happen to use 'merge' 4512 ### for revision undoing is somewhat unnatural anyway, so I'm 4513 ### finding myself having little interest in caring too much about 4514 ### this. That said, if we had a way of storing reverse merge 4515 ### ranges, we'd be in good shape either way. 4516*/ 4517#ifdef SVN_MERGE__ALLOW_ALL_FORWARD_MERGES_FROM_SELF 4518 { 4519 /* ### Don't consider implicit mergeinfo. */ 4520 child->remaining_ranges = svn_rangelist_dup(explicit_rangelist, 4521 pool); 4522 } 4523#else 4524 { 4525 /* Based on CHILD's TARGET_MERGEINFO there are ranges to merge. 4526 Check CHILD's implicit mergeinfo to see if these remaining 4527 ranges are represented there. */ 4528 SVN_ERR(ensure_implicit_mergeinfo(parent, 4529 child, 4530 child_inherits_implicit, 4531 revision1, 4532 revision2, 4533 ra_session, 4534 ctx, 4535 result_pool, 4536 scratch_pool)); 4537 4538 target_implicit_rangelist = svn_hash_gets(child->implicit_mergeinfo, 4539 mergeinfo_path); 4540 if (target_implicit_rangelist) 4541 SVN_ERR(svn_rangelist_remove(&(child->remaining_ranges), 4542 target_implicit_rangelist, 4543 explicit_rangelist, 4544 FALSE, result_pool)); 4545 else 4546 child->remaining_ranges = svn_rangelist_dup(explicit_rangelist, 4547 result_pool); 4548 } 4549#endif 4550 } 4551 4552 return SVN_NO_ERROR; 4553} 4554 4555/* Helper for do_file_merge and do_directory_merge (by way of 4556 populate_remaining_ranges() for the latter). 4557 4558 Determine what portions of SOURCE have already 4559 been merged to CHILD->ABSPATH and populate CHILD->REMAINING_RANGES with 4560 the ranges that still need merging. 4561 4562 SOURCE and CTX are all cascaded from the caller's arguments of the same 4563 names. Note that this means SOURCE adheres to the requirements noted in 4564 `MERGEINFO MERGE SOURCE NORMALIZATION'. 4565 4566 CHILD represents a working copy path which is the merge target or one of 4567 the target's subtrees. If not NULL, PARENT is CHILD's nearest path-wise 4568 ancestor - see 'THE CHILDREN_WITH_MERGEINFO ARRAY'. TARGET_MERGEINFO is 4569 the working mergeinfo on CHILD. 4570 4571 RA_SESSION is the session for the younger of SOURCE->loc1 and 4572 SOURCE->loc2. 4573 4574 If the function needs to consider CHILD->IMPLICIT_MERGEINFO and 4575 CHILD_INHERITS_IMPLICIT is true, then set CHILD->IMPLICIT_MERGEINFO to the 4576 mergeinfo inherited from PARENT->IMPLICIT_MERGEINFO. Otherwise contact 4577 the repository for CHILD->IMPLICIT_MERGEINFO. 4578 4579 If not null, IMPLICIT_SRC_GAP is the gap, if any, in the natural history 4580 of SOURCE, see merge_cmd_baton_t.implicit_src_gap. 4581 4582 SCRATCH_POOL is used for all temporary allocations. Changes to CHILD and 4583 PARENT are made in RESULT_POOL. 4584 4585 NOTE: This should only be called when honoring mergeinfo. 4586 4587 NOTE: If PARENT is present then this function must have previously been 4588 called for PARENT, i.e. if populate_remaining_ranges() is calling this 4589 function for a set of svn_client__merge_path_t* the calls must be made 4590 in depth-first order. 4591 4592 NOTE: When performing reverse merges, return 4593 SVN_ERR_CLIENT_NOT_READY_TO_MERGE if both locations in SOURCE and 4594 CHILD->ABSPATH are all on the same line of history but CHILD->ABSPATH's 4595 base revision is older than the SOURCE->rev1:rev2 range, see comment re 4596 issue #2973 below. 4597*/ 4598static svn_error_t * 4599calculate_remaining_ranges(svn_client__merge_path_t *parent, 4600 svn_client__merge_path_t *child, 4601 const merge_source_t *source, 4602 svn_mergeinfo_t target_mergeinfo, 4603 const apr_array_header_t *implicit_src_gap, 4604 svn_boolean_t child_inherits_implicit, 4605 svn_ra_session_t *ra_session, 4606 svn_client_ctx_t *ctx, 4607 apr_pool_t *result_pool, 4608 apr_pool_t *scratch_pool) 4609{ 4610 const svn_client__pathrev_t *primary_src 4611 = (source->loc1->rev < source->loc2->rev) ? source->loc2 : source->loc1; 4612 const char *mergeinfo_path = svn_client__pathrev_fspath(primary_src, 4613 scratch_pool); 4614 /* Intersection of TARGET_MERGEINFO and the merge history 4615 described by SOURCE. */ 4616 svn_rangelist_t *target_rangelist; 4617 svn_revnum_t child_base_revision; 4618 4619 /* Since this function should only be called when honoring mergeinfo and 4620 * SOURCE adheres to the requirements noted in 'MERGEINFO MERGE SOURCE 4621 * NORMALIZATION', SOURCE must be 'ancestral'. */ 4622 SVN_ERR_ASSERT(source->ancestral); 4623 4624 /* Determine which of the requested ranges to consider merging... */ 4625 4626 /* Set TARGET_RANGELIST to the portion of TARGET_MERGEINFO that refers 4627 to SOURCE (excluding any gap in SOURCE): first get all ranges from 4628 TARGET_MERGEINFO that refer to the path of SOURCE, and then prune 4629 any ranges that lie in the gap in SOURCE. 4630 4631 ### [JAF] In fact, that may still leave some ranges that lie entirely 4632 outside the range of SOURCE; it seems we don't care about that. */ 4633 if (target_mergeinfo) 4634 target_rangelist = svn_hash_gets(target_mergeinfo, mergeinfo_path); 4635 else 4636 target_rangelist = NULL; 4637 if (implicit_src_gap && target_rangelist) 4638 { 4639 /* Remove any mergeinfo referring to the 'gap' in SOURCE, as that 4640 mergeinfo doesn't really refer to SOURCE at all but instead 4641 refers to locations that are non-existent or on a different 4642 line of history. (Issue #3242.) */ 4643 SVN_ERR(svn_rangelist_remove(&target_rangelist, 4644 implicit_src_gap, target_rangelist, 4645 FALSE, result_pool)); 4646 } 4647 4648 /* Initialize CHILD->REMAINING_RANGES and filter out revisions already 4649 merged (or, in the case of reverse merges, ranges not yet merged). */ 4650 SVN_ERR(filter_merged_revisions(parent, child, mergeinfo_path, 4651 target_rangelist, 4652 source->loc1->rev, source->loc2->rev, 4653 child_inherits_implicit, 4654 ra_session, ctx, result_pool, 4655 scratch_pool)); 4656 4657 /* Issue #2973 -- from the continuing series of "Why, since the advent of 4658 merge tracking, allowing merges into mixed rev and locally modified 4659 working copies isn't simple and could be considered downright evil". 4660 4661 If reverse merging a range to the WC path represented by CHILD, from 4662 that path's own history, where the path inherits no locally modified 4663 mergeinfo from its WC parents (i.e. there is no uncommitted merge to 4664 the WC), and the path's base revision is older than the range, then 4665 the merge will always be a no-op. This is because we only allow reverse 4666 merges of ranges in the path's explicit or natural mergeinfo and a 4667 reverse merge from the path's future history obviously isn't going to be 4668 in either, hence the no-op. 4669 4670 The problem is two-fold. First, in a mixed rev WC, the change we 4671 want to revert might actually be to some child of the target path 4672 which is at a younger base revision. Sure, we can merge directly 4673 to that child or update the WC or even use --ignore-ancestry and then 4674 successfully run the reverse merge, but that gets to the second 4675 problem: Those courses of action are not very obvious. Before 1.5 if 4676 a user committed a change that didn't touch the commit target, then 4677 immediately decided to revert that change via a reverse merge it would 4678 just DTRT. But with the advent of merge tracking the user gets a no-op. 4679 4680 So in the name of user friendliness, return an error suggesting a helpful 4681 course of action. 4682 */ 4683 SVN_ERR(svn_wc__node_get_base(NULL, &child_base_revision, 4684 NULL, NULL, NULL, NULL, 4685 ctx->wc_ctx, child->abspath, 4686 TRUE /* ignore_enoent */, 4687 FALSE /* show_hidden */, 4688 scratch_pool, scratch_pool)); 4689 /* If CHILD has no base revision then it hasn't been committed yet, so it 4690 can't have any "future" history. */ 4691 if (SVN_IS_VALID_REVNUM(child_base_revision) 4692 && ((child->remaining_ranges)->nelts == 0) /* Inoperative merge */ 4693 && (source->loc2->rev < source->loc1->rev) /* Reverse merge */ 4694 && (child_base_revision <= source->loc2->rev)) /* From CHILD's future */ 4695 { 4696 /* Hmmm, an inoperative reverse merge from the "future". If it is 4697 from our own future return a helpful error. */ 4698 svn_error_t *err; 4699 svn_client__pathrev_t *start_loc; 4700 4701 err = svn_client__repos_location(&start_loc, 4702 ra_session, 4703 source->loc1, 4704 child_base_revision, 4705 ctx, scratch_pool, scratch_pool); 4706 if (err) 4707 { 4708 if (err->apr_err == SVN_ERR_FS_NOT_FOUND 4709 || err->apr_err == SVN_ERR_CLIENT_UNRELATED_RESOURCES) 4710 svn_error_clear(err); 4711 else 4712 return svn_error_trace(err); 4713 } 4714 else 4715 { 4716 const char *url; 4717 4718 SVN_ERR(svn_wc__node_get_url(&url, ctx->wc_ctx, child->abspath, 4719 scratch_pool, scratch_pool)); 4720 if (strcmp(start_loc->url, url) == 0) 4721 return svn_error_create(SVN_ERR_CLIENT_MERGE_UPDATE_REQUIRED, NULL, 4722 _("Cannot reverse-merge a range from a " 4723 "path's own future history; try " 4724 "updating first")); 4725 } 4726 } 4727 4728 return SVN_NO_ERROR; 4729} 4730 4731/* Helper for populate_remaining_ranges(). 4732 4733 SOURCE is cascaded from the arguments of the same name in 4734 populate_remaining_ranges(). 4735 4736 Note: The following comments assume a forward merge, i.e. 4737 SOURCE->loc1->rev < SOURCE->loc2->rev. If this is a reverse merge then 4738 all the following comments still apply, but with SOURCE->loc1 switched 4739 with SOURCE->loc2. 4740 4741 Like populate_remaining_ranges(), SOURCE must adhere to the restrictions 4742 documented in 'MERGEINFO MERGE SOURCE NORMALIZATION'. These restrictions 4743 allow for a *single* gap in SOURCE, GAP_REV1:GAP_REV2 exclusive:inclusive 4744 (where SOURCE->loc1->rev == GAP_REV1 <= GAP_REV2 < SOURCE->loc2->rev), 4745 if SOURCE->loc2->url@(GAP_REV2+1) was copied from SOURCE->loc1. If such 4746 a gap exists, set *GAP_START and *GAP_END to the starting and ending 4747 revisions of the gap. Otherwise set both to SVN_INVALID_REVNUM. 4748 4749 For example, if the natural history of URL@2:URL@9 is 'trunk/:2,7-9' this 4750 would indicate that trunk@7 was copied from trunk@2. This function would 4751 return GAP_START:GAP_END of 2:6 in this case. Note that a path 'trunk' 4752 might exist at r3-6, but it would not be on the same line of history as 4753 trunk@9. 4754 4755 ### GAP_START is basically redundant, as (if there is a gap at all) it is 4756 necessarily the older revision of SOURCE. 4757 4758 RA_SESSION is an open RA session to the repository in which SOURCE lives. 4759*/ 4760static svn_error_t * 4761find_gaps_in_merge_source_history(svn_revnum_t *gap_start, 4762 svn_revnum_t *gap_end, 4763 const merge_source_t *source, 4764 svn_ra_session_t *ra_session, 4765 svn_client_ctx_t *ctx, 4766 apr_pool_t *scratch_pool) 4767{ 4768 svn_mergeinfo_t implicit_src_mergeinfo; 4769 svn_revnum_t old_rev = MIN(source->loc1->rev, source->loc2->rev); 4770 const svn_client__pathrev_t *primary_src 4771 = (source->loc1->rev < source->loc2->rev) ? source->loc2 : source->loc1; 4772 const char *merge_src_fspath = svn_client__pathrev_fspath(primary_src, 4773 scratch_pool); 4774 svn_rangelist_t *rangelist; 4775 4776 SVN_ERR_ASSERT(source->ancestral); 4777 4778 /* Start by assuming there is no gap. */ 4779 *gap_start = *gap_end = SVN_INVALID_REVNUM; 4780 4781 /* Easy out: There can't be a gap between adjacent revisions. */ 4782 if (abs(source->loc1->rev - source->loc2->rev) == 1) 4783 return SVN_NO_ERROR; 4784 4785 /* Get SOURCE as mergeinfo. */ 4786 SVN_ERR(svn_client__get_history_as_mergeinfo(&implicit_src_mergeinfo, NULL, 4787 primary_src, 4788 primary_src->rev, old_rev, 4789 ra_session, 4790 ctx, scratch_pool)); 4791 4792 rangelist = svn_hash_gets(implicit_src_mergeinfo, merge_src_fspath); 4793 4794 if (!rangelist) /* ### Can we ever not find a rangelist? */ 4795 return SVN_NO_ERROR; 4796 4797 /* A gap in natural history can result from either a copy or 4798 a rename. If from a copy then history as mergeinfo will look 4799 something like this: 4800 4801 '/trunk:X,Y-Z' 4802 4803 If from a rename it will look like this: 4804 4805 '/trunk_old_name:X' 4806 '/trunk_new_name:Y-Z' 4807 4808 In both cases the gap, if it exists, is M-N, where M = X + 1 and 4809 N = Y - 1. 4810 4811 Note that per the rules of 'MERGEINFO MERGE SOURCE NORMALIZATION' we 4812 should never have multiple gaps, e.g. if we see anything like the 4813 following then something is quite wrong: 4814 4815 '/trunk_old_name:A,B-C' 4816 '/trunk_new_name:D-E' 4817 */ 4818 4819 if (rangelist->nelts > 1) /* Copy */ 4820 { 4821 const svn_merge_range_t *gap; 4822 /* As mentioned above, multiple gaps *shouldn't* be possible. */ 4823 SVN_ERR_ASSERT(apr_hash_count(implicit_src_mergeinfo) == 1); 4824 4825 gap = APR_ARRAY_IDX(rangelist, rangelist->nelts - 1, 4826 const svn_merge_range_t *); 4827 4828 *gap_start = MIN(source->loc1->rev, source->loc2->rev); 4829 *gap_end = gap->start; 4830 4831 /* ### Issue #4132: 4832 ### This assertion triggers in merge_tests.py svnmucc_abuse_1() 4833 ### when a node is replaced by an older copy of itself. 4834 4835 BH: I think we should review this and the 'rename' case to find 4836 out which behavior we really want, and if we can really 4837 determine what happened this way. */ 4838 SVN_ERR_ASSERT(*gap_start < *gap_end); 4839 } 4840 else if (apr_hash_count(implicit_src_mergeinfo) > 1) /* Rename */ 4841 { 4842 svn_rangelist_t *requested_rangelist = 4843 svn_rangelist__initialize(MIN(source->loc1->rev, source->loc2->rev), 4844 MAX(source->loc1->rev, source->loc2->rev), 4845 TRUE, scratch_pool); 4846 svn_rangelist_t *implicit_rangelist = 4847 apr_array_make(scratch_pool, 2, sizeof(svn_merge_range_t *)); 4848 svn_rangelist_t *gap_rangelist; 4849 4850 SVN_ERR(svn_rangelist__merge_many(implicit_rangelist, 4851 implicit_src_mergeinfo, 4852 scratch_pool, scratch_pool)); 4853 SVN_ERR(svn_rangelist_remove(&gap_rangelist, implicit_rangelist, 4854 requested_rangelist, FALSE, 4855 scratch_pool)); 4856 4857 /* If there is anything left it is the gap. */ 4858 if (gap_rangelist->nelts) 4859 { 4860 svn_merge_range_t *gap_range = 4861 APR_ARRAY_IDX(gap_rangelist, 0, svn_merge_range_t *); 4862 4863 *gap_start = gap_range->start; 4864 *gap_end = gap_range->end; 4865 } 4866 } 4867 4868 SVN_ERR_ASSERT(*gap_start == MIN(source->loc1->rev, source->loc2->rev) 4869 || (*gap_start == SVN_INVALID_REVNUM 4870 && *gap_end == SVN_INVALID_REVNUM)); 4871 return SVN_NO_ERROR; 4872} 4873 4874/* Helper for do_directory_merge(). 4875 4876 For each (svn_client__merge_path_t *) child in CHILDREN_WITH_MERGEINFO, 4877 populate that child's 'remaining_ranges' list with (### ... what?), 4878 and populate that child's 'implicit_mergeinfo' with its implicit 4879 mergeinfo (natural history). CHILDREN_WITH_MERGEINFO is expected 4880 to be sorted in depth first order and each child must be processed in 4881 that order. The inheritability of all calculated ranges is TRUE. 4882 4883 If mergeinfo is being honored (based on MERGE_B -- see HONOR_MERGEINFO() 4884 for how this is determined), this function will actually try to be 4885 intelligent about populating remaining_ranges list. Otherwise, it 4886 will claim that each child has a single remaining range, from 4887 SOURCE->rev1, to SOURCE->rev2. 4888 ### We also take the short-cut if doing record-only. Why? 4889 4890 SCRATCH_POOL is used for all temporary allocations. Changes to 4891 CHILDREN_WITH_MERGEINFO are made in RESULT_POOL. 4892 4893 Note that if SOURCE->rev1 > SOURCE->rev2, then each child's remaining_ranges 4894 member does not adhere to the API rules for rangelists described in 4895 svn_mergeinfo.h -- See svn_client__merge_path_t. 4896 4897 See `MERGEINFO MERGE SOURCE NORMALIZATION' for more requirements 4898 around SOURCE. 4899*/ 4900static svn_error_t * 4901populate_remaining_ranges(apr_array_header_t *children_with_mergeinfo, 4902 const merge_source_t *source, 4903 svn_ra_session_t *ra_session, 4904 merge_cmd_baton_t *merge_b, 4905 apr_pool_t *result_pool, 4906 apr_pool_t *scratch_pool) 4907{ 4908 apr_pool_t *iterpool = svn_pool_create(scratch_pool); 4909 int i; 4910 svn_revnum_t gap_start, gap_end; 4911 4912 /* If we aren't honoring mergeinfo or this is a --record-only merge, 4913 we'll make quick work of this by simply adding dummy SOURCE->rev1:rev2 4914 ranges for all children. */ 4915 if (! HONOR_MERGEINFO(merge_b) || merge_b->record_only) 4916 { 4917 for (i = 0; i < children_with_mergeinfo->nelts; i++) 4918 { 4919 svn_client__merge_path_t *child = 4920 APR_ARRAY_IDX(children_with_mergeinfo, i, 4921 svn_client__merge_path_t *); 4922 4923 svn_pool_clear(iterpool); 4924 4925 /* Issue #3646 'record-only merges create self-referential 4926 mergeinfo'. Get the merge target's implicit mergeinfo (natural 4927 history). We'll use it later to avoid setting self-referential 4928 mergeinfo -- see filter_natural_history_from_mergeinfo(). */ 4929 if (i == 0) /* First item is always the merge target. */ 4930 { 4931 SVN_ERR(get_full_mergeinfo(NULL, /* child->pre_merge_mergeinfo */ 4932 &(child->implicit_mergeinfo), 4933 NULL, /* child->inherited_mergeinfo */ 4934 svn_mergeinfo_inherited, ra_session, 4935 child->abspath, 4936 MAX(source->loc1->rev, 4937 source->loc2->rev), 4938 MIN(source->loc1->rev, 4939 source->loc2->rev), 4940 merge_b->ctx, result_pool, 4941 iterpool)); 4942 } 4943 else 4944 { 4945 /* Issue #3443 - Subtrees of the merge target can inherit 4946 their parent's implicit mergeinfo in most cases. */ 4947 svn_client__merge_path_t *parent 4948 = find_nearest_ancestor(children_with_mergeinfo, 4949 FALSE, child->abspath); 4950 svn_boolean_t child_inherits_implicit; 4951 4952 /* If CHILD is a subtree then its parent must be in 4953 CHILDREN_WITH_MERGEINFO, see the global comment 4954 'THE CHILDREN_WITH_MERGEINFO ARRAY'. */ 4955 SVN_ERR_ASSERT(parent); 4956 4957 child_inherits_implicit = (parent && !child->switched); 4958 SVN_ERR(ensure_implicit_mergeinfo(parent, child, 4959 child_inherits_implicit, 4960 source->loc1->rev, 4961 source->loc2->rev, 4962 ra_session, merge_b->ctx, 4963 result_pool, iterpool)); 4964 } 4965 4966 child->remaining_ranges = svn_rangelist__initialize(source->loc1->rev, 4967 source->loc2->rev, 4968 TRUE, 4969 result_pool); 4970 } 4971 svn_pool_destroy(iterpool); 4972 return SVN_NO_ERROR; 4973 } 4974 4975 /* If, in the merge source's history, there was a copy from an older 4976 revision, then SOURCE->loc2->url won't exist at some range M:N, where 4977 SOURCE->loc1->rev < M < N < SOURCE->loc2->rev. The rules of 'MERGEINFO 4978 MERGE SOURCE NORMALIZATION' allow this, but we must ignore these gaps 4979 when calculating what ranges remain to be merged from SOURCE. If we 4980 don't and try to merge any part of SOURCE->loc2->url@M:N we would 4981 break the editor since no part of that actually exists. See 4982 http://svn.haxx.se/dev/archive-2008-11/0618.shtml. 4983 4984 Find the gaps in the merge target's history, if any. Eventually 4985 we will adjust CHILD->REMAINING_RANGES such that we don't describe 4986 non-existent paths to the editor. */ 4987 SVN_ERR(find_gaps_in_merge_source_history(&gap_start, &gap_end, 4988 source, 4989 ra_session, merge_b->ctx, 4990 iterpool)); 4991 4992 /* Stash any gap in the merge command baton, we'll need it later when 4993 recording mergeinfo describing this merge. */ 4994 if (SVN_IS_VALID_REVNUM(gap_start) && SVN_IS_VALID_REVNUM(gap_end)) 4995 merge_b->implicit_src_gap = svn_rangelist__initialize(gap_start, gap_end, 4996 TRUE, result_pool); 4997 4998 for (i = 0; i < children_with_mergeinfo->nelts; i++) 4999 { 5000 svn_client__merge_path_t *child = 5001 APR_ARRAY_IDX(children_with_mergeinfo, i, svn_client__merge_path_t *); 5002 const char *child_repos_path 5003 = svn_dirent_skip_ancestor(merge_b->target->abspath, child->abspath); 5004 merge_source_t child_source; 5005 svn_client__merge_path_t *parent = NULL; 5006 svn_boolean_t child_inherits_implicit; 5007 5008 svn_pool_clear(iterpool); 5009 5010 /* If the path is absent don't do subtree merge either. */ 5011 SVN_ERR_ASSERT(child); 5012 if (child->absent) 5013 continue; 5014 5015 SVN_ERR_ASSERT(child_repos_path != NULL); 5016 child_source.loc1 = svn_client__pathrev_join_relpath( 5017 source->loc1, child_repos_path, iterpool); 5018 child_source.loc2 = svn_client__pathrev_join_relpath( 5019 source->loc2, child_repos_path, iterpool); 5020 /* ### Is the child 'ancestral' over the same revision range? It's 5021 * not necessarily true that a child is 'ancestral' if the parent is, 5022 * nor that it's not if the parent is not. However, here we claim 5023 * that it is. Before we had this 'ancestral' field that we need to 5024 * set explicitly, the claim was implicit. Either way, the impact is 5025 * that we might pass calculate_remaining_ranges() a source that is 5026 * not in fact 'ancestral' (despite its 'ancestral' field being true), 5027 * contrary to its doc-string. */ 5028 child_source.ancestral = source->ancestral; 5029 5030 /* Get the explicit/inherited mergeinfo for CHILD. If CHILD is the 5031 merge target then also get its implicit mergeinfo. Otherwise defer 5032 this until we know it is absolutely necessary, since it requires an 5033 expensive round trip communication with the server. */ 5034 SVN_ERR(get_full_mergeinfo( 5035 child->pre_merge_mergeinfo ? NULL : &(child->pre_merge_mergeinfo), 5036 /* Get implicit only for merge target. */ 5037 (i == 0) ? &(child->implicit_mergeinfo) : NULL, 5038 &(child->inherited_mergeinfo), 5039 svn_mergeinfo_inherited, ra_session, 5040 child->abspath, 5041 MAX(source->loc1->rev, source->loc2->rev), 5042 MIN(source->loc1->rev, source->loc2->rev), 5043 merge_b->ctx, result_pool, iterpool)); 5044 5045 /* If CHILD isn't the merge target find its parent. */ 5046 if (i > 0) 5047 { 5048 parent = find_nearest_ancestor(children_with_mergeinfo, 5049 FALSE, child->abspath); 5050 /* If CHILD is a subtree then its parent must be in 5051 CHILDREN_WITH_MERGEINFO, see the global comment 5052 'THE CHILDREN_WITH_MERGEINFO ARRAY'. */ 5053 SVN_ERR_ASSERT(parent); 5054 } 5055 5056 /* Issue #3443 - Can CHILD inherit PARENT's implicit mergeinfo, saving 5057 us from having to ask the repos? The only time we can't do this is if 5058 CHILD is the merge target and so there is no PARENT to inherit from 5059 or if CHILD is the root of a switched subtree, in which case PARENT 5060 exists but is not CHILD's repository parent. */ 5061 child_inherits_implicit = (parent && !child->switched); 5062 5063 SVN_ERR(calculate_remaining_ranges(parent, child, 5064 &child_source, 5065 child->pre_merge_mergeinfo, 5066 merge_b->implicit_src_gap, 5067 child_inherits_implicit, 5068 ra_session, 5069 merge_b->ctx, result_pool, 5070 iterpool)); 5071 5072 /* Deal with any gap in SOURCE's natural history. 5073 5074 If the gap is a proper subset of CHILD->REMAINING_RANGES then we can 5075 safely ignore it since we won't describe this path/rev pair. 5076 5077 If the gap exactly matches or is a superset of a range in 5078 CHILD->REMAINING_RANGES then we must remove that range so we don't 5079 attempt to describe non-existent paths via the reporter, this will 5080 break the editor and our merge. 5081 5082 If the gap adjoins or overlaps a range in CHILD->REMAINING_RANGES 5083 then we must *add* the gap so we span the missing revisions. */ 5084 if (child->remaining_ranges->nelts 5085 && merge_b->implicit_src_gap) 5086 { 5087 int j; 5088 svn_boolean_t proper_subset = FALSE; 5089 svn_boolean_t overlaps_or_adjoins = FALSE; 5090 5091 /* If this is a reverse merge reorder CHILD->REMAINING_RANGES 5092 so it will work with the svn_rangelist_* APIs below. */ 5093 if (source->loc1->rev > source->loc2->rev) 5094 SVN_ERR(svn_rangelist_reverse(child->remaining_ranges, iterpool)); 5095 5096 for (j = 0; j < child->remaining_ranges->nelts; j++) 5097 { 5098 svn_merge_range_t *range 5099 = APR_ARRAY_IDX(child->remaining_ranges, j, svn_merge_range_t *); 5100 5101 if ((range->start <= gap_start && gap_end < range->end) 5102 || (range->start < gap_start && gap_end <= range->end)) 5103 { 5104 proper_subset = TRUE; 5105 break; 5106 } 5107 else if ((gap_start == range->start) && (range->end == gap_end)) 5108 { 5109 break; 5110 } 5111 else if (gap_start <= range->end && range->start <= gap_end) 5112 /* intersect */ 5113 { 5114 overlaps_or_adjoins = TRUE; 5115 break; 5116 } 5117 } 5118 5119 if (!proper_subset) 5120 { 5121 /* We need to make adjustments. Remove from, or add the gap 5122 to, CHILD->REMAINING_RANGES as appropriate. */ 5123 5124 if (overlaps_or_adjoins) 5125 SVN_ERR(svn_rangelist_merge2(child->remaining_ranges, 5126 merge_b->implicit_src_gap, 5127 result_pool, iterpool)); 5128 else /* equals == TRUE */ 5129 SVN_ERR(svn_rangelist_remove(&(child->remaining_ranges), 5130 merge_b->implicit_src_gap, 5131 child->remaining_ranges, FALSE, 5132 result_pool)); 5133 } 5134 5135 if (source->loc1->rev > source->loc2->rev) /* Reverse merge */ 5136 SVN_ERR(svn_rangelist_reverse(child->remaining_ranges, iterpool)); 5137 } 5138 } 5139 5140 svn_pool_destroy(iterpool); 5141 return SVN_NO_ERROR; 5142} 5143 5144 5145/*-----------------------------------------------------------------------*/ 5146 5147/*** Other Helper Functions ***/ 5148 5149/* Calculate the new mergeinfo for the target tree rooted at TARGET_ABSPATH 5150 based on MERGES (a mapping of absolute WC paths to rangelists representing 5151 a merge from the source SOURCE_FSPATH). 5152 5153 If RESULT_CATALOG is NULL, then record the new mergeinfo in the WC (at, 5154 and possibly below, TARGET_ABSPATH). 5155 5156 If RESULT_CATALOG is not NULL, then don't record the new mergeinfo on the 5157 WC, but instead record it in RESULT_CATALOG, where the keys are absolute 5158 working copy paths and the values are the new mergeinfos for each. 5159 Allocate additions to RESULT_CATALOG in pool which RESULT_CATALOG was 5160 created in. */ 5161static svn_error_t * 5162update_wc_mergeinfo(svn_mergeinfo_catalog_t result_catalog, 5163 const char *target_abspath, 5164 const char *source_fspath, 5165 apr_hash_t *merges, 5166 svn_boolean_t is_rollback, 5167 svn_client_ctx_t *ctx, 5168 apr_pool_t *scratch_pool) 5169{ 5170 apr_pool_t *iterpool = svn_pool_create(scratch_pool); 5171 apr_hash_index_t *hi; 5172 5173 /* Combine the mergeinfo for the revision range just merged into 5174 the WC with its on-disk mergeinfo. */ 5175 for (hi = apr_hash_first(scratch_pool, merges); hi; hi = apr_hash_next(hi)) 5176 { 5177 const char *local_abspath = svn__apr_hash_index_key(hi); 5178 svn_rangelist_t *ranges = svn__apr_hash_index_val(hi); 5179 svn_rangelist_t *rangelist; 5180 svn_error_t *err; 5181 const char *local_abspath_rel_to_target; 5182 const char *fspath; 5183 svn_mergeinfo_t mergeinfo; 5184 5185 svn_pool_clear(iterpool); 5186 5187 /* As some of the merges may've changed the WC's mergeinfo, get 5188 a fresh copy before using it to update the WC's mergeinfo. */ 5189 err = svn_client__parse_mergeinfo(&mergeinfo, ctx->wc_ctx, 5190 local_abspath, iterpool, iterpool); 5191 5192 /* If a directory PATH was skipped because it is missing or was 5193 obstructed by an unversioned item then there's nothing we can 5194 do with that, so skip it. */ 5195 if (err) 5196 { 5197 if (err->apr_err == SVN_ERR_WC_NOT_LOCKED 5198 || err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND) 5199 { 5200 svn_error_clear(err); 5201 continue; 5202 } 5203 else 5204 { 5205 return svn_error_trace(err); 5206 } 5207 } 5208 5209 /* If we are attempting to set empty revision range override mergeinfo 5210 on a path with no explicit mergeinfo, we first need the 5211 mergeinfo that path inherits. */ 5212 if (mergeinfo == NULL && ranges->nelts == 0) 5213 { 5214 SVN_ERR(svn_client__get_wc_mergeinfo(&mergeinfo, NULL, 5215 svn_mergeinfo_nearest_ancestor, 5216 local_abspath, NULL, NULL, 5217 FALSE, ctx, iterpool, iterpool)); 5218 } 5219 5220 if (mergeinfo == NULL) 5221 mergeinfo = apr_hash_make(iterpool); 5222 5223 local_abspath_rel_to_target = svn_dirent_skip_ancestor(target_abspath, 5224 local_abspath); 5225 SVN_ERR_ASSERT(local_abspath_rel_to_target != NULL); 5226 fspath = svn_fspath__join(source_fspath, 5227 local_abspath_rel_to_target, 5228 iterpool); 5229 rangelist = svn_hash_gets(mergeinfo, fspath); 5230 if (rangelist == NULL) 5231 rangelist = apr_array_make(iterpool, 0, sizeof(svn_merge_range_t *)); 5232 5233 if (is_rollback) 5234 { 5235 ranges = svn_rangelist_dup(ranges, iterpool); 5236 SVN_ERR(svn_rangelist_reverse(ranges, iterpool)); 5237 SVN_ERR(svn_rangelist_remove(&rangelist, ranges, rangelist, 5238 FALSE, 5239 iterpool)); 5240 } 5241 else 5242 { 5243 SVN_ERR(svn_rangelist_merge2(rangelist, ranges, iterpool, iterpool)); 5244 } 5245 /* Update the mergeinfo by adjusting the path's rangelist. */ 5246 svn_hash_sets(mergeinfo, fspath, rangelist); 5247 5248 if (is_rollback && apr_hash_count(mergeinfo) == 0) 5249 mergeinfo = NULL; 5250 5251 svn_mergeinfo__remove_empty_rangelists(mergeinfo, scratch_pool); 5252 5253 if (result_catalog) 5254 { 5255 svn_mergeinfo_t existing_mergeinfo = 5256 svn_hash_gets(result_catalog, local_abspath); 5257 apr_pool_t *result_catalog_pool = apr_hash_pool_get(result_catalog); 5258 5259 if (existing_mergeinfo) 5260 SVN_ERR(svn_mergeinfo_merge2(mergeinfo, existing_mergeinfo, 5261 result_catalog_pool, scratch_pool)); 5262 svn_hash_sets(result_catalog, 5263 apr_pstrdup(result_catalog_pool, local_abspath), 5264 svn_mergeinfo_dup(mergeinfo, result_catalog_pool)); 5265 } 5266 else 5267 { 5268 err = svn_client__record_wc_mergeinfo(local_abspath, mergeinfo, 5269 TRUE, ctx, iterpool); 5270 5271 if (err && err->apr_err == SVN_ERR_ENTRY_NOT_FOUND) 5272 { 5273 /* PATH isn't just missing, it's not even versioned as far 5274 as this working copy knows. But it was included in 5275 MERGES, which means that the server knows about it. 5276 Likely we don't have access to the source due to authz 5277 restrictions. For now just clear the error and 5278 continue... 5279 5280 ### TODO: Set non-inheritable mergeinfo on PATH's immediate 5281 ### parent and normal mergeinfo on PATH's siblings which we 5282 ### do have access to. */ 5283 svn_error_clear(err); 5284 } 5285 else 5286 SVN_ERR(err); 5287 } 5288 } 5289 5290 svn_pool_destroy(iterpool); 5291 return SVN_NO_ERROR; 5292} 5293 5294/* Helper for record_mergeinfo_for_dir_merge(). 5295 5296 Record override mergeinfo on any paths skipped during a merge. 5297 5298 Set empty mergeinfo on each path in MERGE_B->SKIPPED_ABSPATHS so the path 5299 does not incorrectly inherit mergeinfo that will later be describing 5300 the merge. 5301 5302 MERGEINFO_PATH and MERGE_B are cascaded from 5303 arguments of the same name in the caller. 5304 5305 IS_ROLLBACK is true if the caller is recording a reverse merge and false 5306 otherwise. RANGELIST is the set of revisions being merged from 5307 MERGEINFO_PATH to MERGE_B->target. */ 5308static svn_error_t * 5309record_skips_in_mergeinfo(const char *mergeinfo_path, 5310 const svn_rangelist_t *rangelist, 5311 svn_boolean_t is_rollback, 5312 merge_cmd_baton_t *merge_b, 5313 apr_pool_t *scratch_pool) 5314{ 5315 apr_hash_index_t *hi; 5316 apr_hash_t *merges; 5317 apr_size_t nbr_skips = apr_hash_count(merge_b->skipped_abspaths); 5318 apr_pool_t *iterpool = svn_pool_create(scratch_pool); 5319 5320 if (nbr_skips == 0) 5321 return SVN_NO_ERROR; 5322 5323 merges = apr_hash_make(scratch_pool); 5324 5325 /* Override the mergeinfo for child paths which weren't actually merged. */ 5326 for (hi = apr_hash_first(scratch_pool, merge_b->skipped_abspaths); hi; 5327 hi = apr_hash_next(hi)) 5328 { 5329 const char *skipped_abspath = svn__apr_hash_index_key(hi); 5330 svn_wc_notify_state_t obstruction_state; 5331 5332 svn_pool_clear(iterpool); 5333 5334 /* Before we override, make sure this is a versioned path, it might 5335 be an external or missing from disk due to authz restrictions. */ 5336 SVN_ERR(perform_obstruction_check(&obstruction_state, NULL, NULL, 5337 NULL, NULL, 5338 merge_b, skipped_abspath, 5339 iterpool)); 5340 if (obstruction_state == svn_wc_notify_state_obstructed 5341 || obstruction_state == svn_wc_notify_state_missing) 5342 continue; 5343 5344 /* Add an empty range list for this path. 5345 5346 ### TODO: This works fine for a file path skipped because it is 5347 ### missing as long as the file's parent directory is present. 5348 ### But missing directory paths skipped are not handled yet, 5349 ### see issue #2915. 5350 5351 ### TODO: An empty range is fine if the skipped path doesn't 5352 ### inherit any mergeinfo from a parent, but if it does 5353 ### we need to account for that. See issue #3440 5354 ### http://subversion.tigris.org/issues/show_bug.cgi?id=3440. */ 5355 svn_hash_sets(merges, skipped_abspath, 5356 apr_array_make(scratch_pool, 0, 5357 sizeof(svn_merge_range_t *))); 5358 5359 /* if (nbr_skips < notify_b->nbr_notifications) 5360 ### Use RANGELIST as the mergeinfo for all children of 5361 ### this path which were not also explicitly 5362 ### skipped? */ 5363 } 5364 SVN_ERR(update_wc_mergeinfo(NULL, merge_b->target->abspath, 5365 mergeinfo_path, merges, 5366 is_rollback, merge_b->ctx, iterpool)); 5367 svn_pool_destroy(iterpool); 5368 return SVN_NO_ERROR; 5369} 5370 5371/* Data for reporting when a merge aborted because of raising conflicts. 5372 */ 5373typedef struct single_range_conflict_report_t 5374{ 5375 /* What sub-range of the requested source raised conflicts? 5376 * The 'inheritable' flag is ignored. */ 5377 merge_source_t *conflicted_range; 5378 /* What sub-range of the requested source remains to be merged? 5379 * NULL if no more. The 'inheritable' flag is ignored. */ 5380 merge_source_t *remaining_source; 5381 5382} single_range_conflict_report_t; 5383 5384/* Create a single_range_conflict_report_t, containing deep copies of 5385 * CONFLICTED_RANGE and REMAINING_SOURCE, allocated in RESULT_POOL. */ 5386static single_range_conflict_report_t * 5387single_range_conflict_report_create(const merge_source_t *conflicted_range, 5388 const merge_source_t *remaining_source, 5389 apr_pool_t *result_pool) 5390{ 5391 single_range_conflict_report_t *report 5392 = apr_palloc(result_pool, sizeof(*report)); 5393 5394 assert(conflicted_range != NULL); 5395 5396 report->conflicted_range = merge_source_dup(conflicted_range, result_pool); 5397 report->remaining_source 5398 = remaining_source ? merge_source_dup(remaining_source, result_pool) 5399 : NULL; 5400 return report; 5401} 5402 5403/* Data for reporting when a merge aborted because of raising conflicts. 5404 * 5405 * ### TODO: More info, including the ranges (or other parameters) the user 5406 * needs to complete the merge. 5407 */ 5408typedef struct conflict_report_t 5409{ 5410 const char *target_abspath; 5411 /* The revision range during which conflicts were raised */ 5412 const merge_source_t *conflicted_range; 5413 /* Was the conflicted range the last range in the whole requested merge? */ 5414 svn_boolean_t was_last_range; 5415} conflict_report_t; 5416 5417/* Return a new conflict_report_t containing deep copies of the parameters, 5418 * allocated in RESULT_POOL. */ 5419static conflict_report_t * 5420conflict_report_create(const char *target_abspath, 5421 const merge_source_t *conflicted_range, 5422 svn_boolean_t was_last_range, 5423 apr_pool_t *result_pool) 5424{ 5425 conflict_report_t *report = apr_palloc(result_pool, sizeof(*report)); 5426 5427 report->target_abspath = apr_pstrdup(result_pool, target_abspath); 5428 report->conflicted_range = merge_source_dup(conflicted_range, result_pool); 5429 report->was_last_range = was_last_range; 5430 return report; 5431} 5432 5433/* Return a deep copy of REPORT, allocated in RESULT_POOL. */ 5434static conflict_report_t * 5435conflict_report_dup(const conflict_report_t *report, 5436 apr_pool_t *result_pool) 5437{ 5438 conflict_report_t *new = apr_pmemdup(result_pool, report, sizeof(*new)); 5439 5440 new->target_abspath = apr_pstrdup(result_pool, report->target_abspath); 5441 new->conflicted_range = merge_source_dup(report->conflicted_range, 5442 result_pool); 5443 return new; 5444} 5445 5446/* Create and return an error structure appropriate for the unmerged 5447 revisions range(s). */ 5448static APR_INLINE svn_error_t * 5449make_merge_conflict_error(conflict_report_t *report, 5450 apr_pool_t *scratch_pool) 5451{ 5452 assert(!report || svn_dirent_is_absolute(report->target_abspath)); 5453 5454 if (report && ! report->was_last_range) 5455 { 5456 svn_error_t *err = svn_error_createf(SVN_ERR_WC_FOUND_CONFLICT, NULL, 5457 _("One or more conflicts were produced while merging r%ld:%ld into\n" 5458 "'%s' --\n" 5459 "resolve all conflicts and rerun the merge to apply the remaining\n" 5460 "unmerged revisions"), 5461 report->conflicted_range->loc1->rev, report->conflicted_range->loc2->rev, 5462 svn_dirent_local_style(report->target_abspath, scratch_pool)); 5463 assert(report->conflicted_range->loc1->rev != report->conflicted_range->loc2->rev); /* ### is a valid case in a 2-URL merge */ 5464 return err; 5465 } 5466 return SVN_NO_ERROR; 5467} 5468 5469/* Helper for do_directory_merge(). 5470 5471 TARGET_WCPATH is a directory and CHILDREN_WITH_MERGEINFO is filled 5472 with paths (svn_client__merge_path_t *) arranged in depth first order, 5473 which have mergeinfo set on them or meet one of the other criteria 5474 defined in get_mergeinfo_paths(). Remove any paths absent from disk 5475 or scheduled for deletion from CHILDREN_WITH_MERGEINFO which are equal to 5476 or are descendants of TARGET_WCPATH by setting those children to NULL. */ 5477static void 5478remove_absent_children(const char *target_wcpath, 5479 apr_array_header_t *children_with_mergeinfo) 5480{ 5481 /* Before we try to override mergeinfo for skipped paths, make sure 5482 the path isn't absent due to authz restrictions, because there's 5483 nothing we can do about those. */ 5484 int i; 5485 for (i = 0; i < children_with_mergeinfo->nelts; i++) 5486 { 5487 svn_client__merge_path_t *child = 5488 APR_ARRAY_IDX(children_with_mergeinfo, i, svn_client__merge_path_t *); 5489 if ((child->absent || child->scheduled_for_deletion) 5490 && svn_dirent_is_ancestor(target_wcpath, child->abspath)) 5491 { 5492 svn_sort__array_delete(children_with_mergeinfo, i--, 1); 5493 } 5494 } 5495} 5496 5497/* Helper for do_directory_merge() to handle the case where a merge editor 5498 drive removes explicit mergeinfo from a subtree of the merge target. 5499 5500 MERGE_B is cascaded from the argument of the same name in 5501 do_directory_merge(). For each path (if any) in 5502 MERGE_B->PATHS_WITH_DELETED_MERGEINFO remove that path from 5503 CHILDREN_WITH_MERGEINFO. 5504 5505 The one exception is for the merge target itself, 5506 MERGE_B->target->abspath, this must always be present in 5507 CHILDREN_WITH_MERGEINFO so this is never removed by this 5508 function. */ 5509static void 5510remove_children_with_deleted_mergeinfo(merge_cmd_baton_t *merge_b, 5511 apr_array_header_t *children_with_mergeinfo) 5512{ 5513 int i; 5514 5515 if (!merge_b->paths_with_deleted_mergeinfo) 5516 return; 5517 5518 /* CHILDREN_WITH_MERGEINFO[0] is the always the merge target 5519 so start at the first child. */ 5520 for (i = 1; i < children_with_mergeinfo->nelts; i++) 5521 { 5522 svn_client__merge_path_t *child = 5523 APR_ARRAY_IDX(children_with_mergeinfo, i, svn_client__merge_path_t *); 5524 5525 if (svn_hash_gets(merge_b->paths_with_deleted_mergeinfo, child->abspath)) 5526 { 5527 svn_sort__array_delete(children_with_mergeinfo, i--, 1); 5528 } 5529 } 5530} 5531 5532/* Helper for do_directory_merge(). 5533 5534 Set up the diff editor report to merge the SOURCE diff 5535 into TARGET_ABSPATH and drive it. 5536 5537 If mergeinfo is not being honored (based on MERGE_B -- see the doc 5538 string for HONOR_MERGEINFO() for how this is determined), then ignore 5539 CHILDREN_WITH_MERGEINFO and merge the SOURCE diff to TARGET_ABSPATH. 5540 5541 If mergeinfo is being honored then perform a history-aware merge, 5542 describing TARGET_ABSPATH and its subtrees to the reporter in such as way 5543 as to avoid repeating merges already performed per the mergeinfo and 5544 natural history of TARGET_ABSPATH and its subtrees. 5545 5546 The ranges that still need to be merged to the TARGET_ABSPATH and its 5547 subtrees are described in CHILDREN_WITH_MERGEINFO, an array of 5548 svn_client__merge_path_t * -- see 'THE CHILDREN_WITH_MERGEINFO ARRAY' 5549 comment at the top of this file for more info. Note that it is possible 5550 TARGET_ABSPATH and/or some of its subtrees need only a subset, or no part, 5551 of SOURCE to be merged. Though there is little point to 5552 calling this function if TARGET_ABSPATH and all its subtrees have already 5553 had SOURCE merged, this will work but is a no-op. 5554 5555 SOURCE->rev1 and SOURCE->rev2 must be bound by the set of remaining_ranges 5556 fields in CHILDREN_WITH_MERGEINFO's elements, specifically: 5557 5558 For forward merges (SOURCE->rev1 < SOURCE->rev2): 5559 5560 1) The first svn_merge_range_t * element of each child's remaining_ranges 5561 array must meet one of the following conditions: 5562 5563 a) The range's start field is greater than or equal to SOURCE->rev2. 5564 5565 b) The range's end field is SOURCE->rev2. 5566 5567 2) Among all the ranges that meet condition 'b' the oldest start 5568 revision must equal SOURCE->rev1. 5569 5570 For reverse merges (SOURCE->rev1 > SOURCE->rev2): 5571 5572 1) The first svn_merge_range_t * element of each child's remaining_ranges 5573 array must meet one of the following conditions: 5574 5575 a) The range's start field is less than or equal to SOURCE->rev2. 5576 5577 b) The range's end field is SOURCE->rev2. 5578 5579 2) Among all the ranges that meet condition 'b' the youngest start 5580 revision must equal SOURCE->rev1. 5581 5582 Note: If the first svn_merge_range_t * element of some subtree child's 5583 remaining_ranges array is the same as the first range of that child's 5584 nearest path-wise ancestor, then the subtree child *will not* be described 5585 to the reporter. 5586 5587 DEPTH, NOTIFY_B, and MERGE_B are cascaded from do_directory_merge(), see 5588 that function for more info. 5589 5590 MERGE_B->ra_session1 and MERGE_B->ra_session2 are RA sessions open to any 5591 URL in the repository of SOURCE; they may be temporarily reparented within 5592 this function. 5593 5594 If SOURCE->ancestral is set, then SOURCE->loc1 must be a 5595 historical ancestor of SOURCE->loc2, or vice-versa (see 5596 `MERGEINFO MERGE SOURCE NORMALIZATION' for more requirements around 5597 SOURCE in this case). 5598*/ 5599static svn_error_t * 5600drive_merge_report_editor(const char *target_abspath, 5601 const merge_source_t *source, 5602 const apr_array_header_t *children_with_mergeinfo, 5603 const svn_diff_tree_processor_t *processor, 5604 svn_depth_t depth, 5605 merge_cmd_baton_t *merge_b, 5606 apr_pool_t *scratch_pool) 5607{ 5608 const svn_ra_reporter3_t *reporter; 5609 const svn_delta_editor_t *diff_editor; 5610 void *diff_edit_baton; 5611 void *report_baton; 5612 svn_revnum_t target_start; 5613 svn_boolean_t honor_mergeinfo = HONOR_MERGEINFO(merge_b); 5614 const char *old_sess1_url, *old_sess2_url; 5615 svn_boolean_t is_rollback = source->loc1->rev > source->loc2->rev; 5616 5617 /* Start with a safe default starting revision for the editor and the 5618 merge target. */ 5619 target_start = source->loc1->rev; 5620 5621 /* If we are honoring mergeinfo the starting revision for the merge target 5622 might not be SOURCE->rev1, in fact the merge target might not need *any* 5623 part of SOURCE merged -- Instead some subtree of the target 5624 needs SOURCE -- So get the right starting revision for the 5625 target. */ 5626 if (honor_mergeinfo) 5627 { 5628 svn_client__merge_path_t *child; 5629 5630 /* CHILDREN_WITH_MERGEINFO must always exist if we are honoring 5631 mergeinfo and must have at least one element (describing the 5632 merge target). */ 5633 SVN_ERR_ASSERT(children_with_mergeinfo); 5634 SVN_ERR_ASSERT(children_with_mergeinfo->nelts); 5635 5636 /* Get the merge target's svn_client__merge_path_t, which is always 5637 the first in the array due to depth first sorting requirement, 5638 see 'THE CHILDREN_WITH_MERGEINFO ARRAY'. */ 5639 child = APR_ARRAY_IDX(children_with_mergeinfo, 0, 5640 svn_client__merge_path_t *); 5641 SVN_ERR_ASSERT(child); 5642 if (child->remaining_ranges->nelts == 0) 5643 { 5644 /* The merge target doesn't need anything merged. */ 5645 target_start = source->loc2->rev; 5646 } 5647 else 5648 { 5649 /* The merge target has remaining revisions to merge. These 5650 ranges may fully or partially overlap the range described 5651 by SOURCE->rev1:rev2 or may not intersect that range at 5652 all. */ 5653 svn_merge_range_t *range = 5654 APR_ARRAY_IDX(child->remaining_ranges, 0, 5655 svn_merge_range_t *); 5656 if ((!is_rollback && range->start > source->loc2->rev) 5657 || (is_rollback && range->start < source->loc2->rev)) 5658 { 5659 /* Merge target's first remaining range doesn't intersect. */ 5660 target_start = source->loc2->rev; 5661 } 5662 else 5663 { 5664 /* Merge target's first remaining range partially or 5665 fully overlaps. */ 5666 target_start = range->start; 5667 } 5668 } 5669 } 5670 5671 SVN_ERR(svn_client__ensure_ra_session_url(&old_sess1_url, 5672 merge_b->ra_session1, 5673 source->loc1->url, scratch_pool)); 5674 /* Temporarily point our second RA session to SOURCE->loc1->url, too. We use 5675 this to request individual file contents. */ 5676 SVN_ERR(svn_client__ensure_ra_session_url(&old_sess2_url, 5677 merge_b->ra_session2, 5678 source->loc1->url, scratch_pool)); 5679 5680 /* Get the diff editor and a reporter with which to, ultimately, 5681 drive it. */ 5682 SVN_ERR(svn_client__get_diff_editor2(&diff_editor, &diff_edit_baton, 5683 merge_b->ra_session2, 5684 depth, 5685 source->loc1->rev, 5686 TRUE /* text_deltas */, 5687 processor, 5688 merge_b->ctx->cancel_func, 5689 merge_b->ctx->cancel_baton, 5690 scratch_pool)); 5691 SVN_ERR(svn_ra_do_diff3(merge_b->ra_session1, 5692 &reporter, &report_baton, source->loc2->rev, 5693 "", depth, merge_b->diff_ignore_ancestry, 5694 TRUE, /* text_deltas */ 5695 source->loc2->url, diff_editor, diff_edit_baton, 5696 scratch_pool)); 5697 5698 /* Drive the reporter. */ 5699 SVN_ERR(reporter->set_path(report_baton, "", target_start, depth, 5700 FALSE, NULL, scratch_pool)); 5701 if (honor_mergeinfo && children_with_mergeinfo) 5702 { 5703 /* Describe children with mergeinfo overlapping this merge 5704 operation such that no repeated diff is retrieved for them from 5705 the repository. */ 5706 int i; 5707 apr_pool_t *iterpool = svn_pool_create(scratch_pool); 5708 5709 /* Start with CHILDREN_WITH_MERGEINFO[1], CHILDREN_WITH_MERGEINFO[0] 5710 is always the merge target (TARGET_ABSPATH). */ 5711 for (i = 1; i < children_with_mergeinfo->nelts; i++) 5712 { 5713 svn_merge_range_t *range; 5714 const char *child_repos_path; 5715 const svn_client__merge_path_t *parent; 5716 const svn_client__merge_path_t *child = 5717 APR_ARRAY_IDX(children_with_mergeinfo, i, 5718 svn_client__merge_path_t *); 5719 5720 SVN_ERR_ASSERT(child); 5721 if (child->absent) 5722 continue; 5723 5724 svn_pool_clear(iterpool); 5725 5726 /* Find this child's nearest wc ancestor with mergeinfo. */ 5727 parent = find_nearest_ancestor(children_with_mergeinfo, 5728 FALSE, child->abspath); 5729 5730 /* If a subtree needs the same range applied as its nearest parent 5731 with mergeinfo or neither the subtree nor this parent need 5732 SOURCE->rev1:rev2 merged, then we don't need to describe the 5733 subtree separately. In the latter case this could break the 5734 editor if child->abspath didn't exist at SOURCE->rev2 and we 5735 attempt to describe it via a reporter set_path call. */ 5736 if (child->remaining_ranges->nelts) 5737 { 5738 range = APR_ARRAY_IDX(child->remaining_ranges, 0, 5739 svn_merge_range_t *); 5740 if ((!is_rollback && range->start > source->loc2->rev) 5741 || (is_rollback && range->start < source->loc2->rev)) 5742 { 5743 /* This child's first remaining range comes after the range 5744 we are currently merging, so skip it. We expect to get 5745 to it in a subsequent call to this function. */ 5746 continue; 5747 } 5748 else if (parent->remaining_ranges->nelts) 5749 { 5750 svn_merge_range_t *parent_range = 5751 APR_ARRAY_IDX(parent->remaining_ranges, 0, 5752 svn_merge_range_t *); 5753 svn_merge_range_t *child_range = 5754 APR_ARRAY_IDX(child->remaining_ranges, 0, 5755 svn_merge_range_t *); 5756 if (parent_range->start == child_range->start) 5757 continue; /* Subtree needs same range as parent. */ 5758 } 5759 } 5760 else /* child->remaining_ranges->nelts == 0*/ 5761 { 5762 /* If both the subtree and its parent need no ranges applied 5763 consider that as the "same ranges" and don't describe 5764 the subtree. */ 5765 if (parent->remaining_ranges->nelts == 0) 5766 continue; 5767 } 5768 5769 /* Ok, we really need to describe this subtree as it needs different 5770 ranges applied than its nearest working copy parent. */ 5771 child_repos_path = svn_dirent_is_child(target_abspath, 5772 child->abspath, 5773 iterpool); 5774 /* This loop is only processing subtrees, so CHILD->ABSPATH 5775 better be a proper child of the merge target. */ 5776 SVN_ERR_ASSERT(child_repos_path); 5777 5778 if ((child->remaining_ranges->nelts == 0) 5779 || (is_rollback && (range->start < source->loc2->rev)) 5780 || (!is_rollback && (range->start > source->loc2->rev))) 5781 { 5782 /* Nothing to merge to this child. We'll claim we have 5783 it up to date so the server doesn't send us 5784 anything. */ 5785 SVN_ERR(reporter->set_path(report_baton, child_repos_path, 5786 source->loc2->rev, depth, FALSE, 5787 NULL, iterpool)); 5788 } 5789 else 5790 { 5791 SVN_ERR(reporter->set_path(report_baton, child_repos_path, 5792 range->start, depth, FALSE, 5793 NULL, iterpool)); 5794 } 5795 } 5796 svn_pool_destroy(iterpool); 5797 } 5798 SVN_ERR(reporter->finish_report(report_baton, scratch_pool)); 5799 5800 /* Point the merge baton's RA sessions back where they were. */ 5801 SVN_ERR(svn_ra_reparent(merge_b->ra_session1, old_sess1_url, scratch_pool)); 5802 SVN_ERR(svn_ra_reparent(merge_b->ra_session2, old_sess2_url, scratch_pool)); 5803 5804 return SVN_NO_ERROR; 5805} 5806 5807/* Iterate over each svn_client__merge_path_t * element in 5808 CHILDREN_WITH_MERGEINFO and, if START_REV is true, find the most inclusive 5809 start revision among those element's first remaining_ranges element. If 5810 START_REV is false, then look for the most inclusive end revision. 5811 5812 If IS_ROLLBACK is true the youngest start or end (as per START_REV) 5813 revision is considered the "most inclusive" otherwise the oldest revision 5814 is. 5815 5816 If none of CHILDREN_WITH_MERGEINFO's elements have any remaining ranges 5817 return SVN_INVALID_REVNUM. */ 5818static svn_revnum_t 5819get_most_inclusive_rev(const apr_array_header_t *children_with_mergeinfo, 5820 svn_boolean_t is_rollback, 5821 svn_boolean_t start_rev) 5822{ 5823 int i; 5824 svn_revnum_t most_inclusive_rev = SVN_INVALID_REVNUM; 5825 5826 for (i = 0; i < children_with_mergeinfo->nelts; i++) 5827 { 5828 svn_client__merge_path_t *child = 5829 APR_ARRAY_IDX(children_with_mergeinfo, i, svn_client__merge_path_t *); 5830 5831 if ((! child) || child->absent) 5832 continue; 5833 if (child->remaining_ranges->nelts > 0) 5834 { 5835 svn_merge_range_t *range = 5836 APR_ARRAY_IDX(child->remaining_ranges, 0, svn_merge_range_t *); 5837 5838 /* Are we looking for the most inclusive start or end rev? */ 5839 svn_revnum_t rev = start_rev ? range->start : range->end; 5840 5841 if ((most_inclusive_rev == SVN_INVALID_REVNUM) 5842 || (is_rollback && (rev > most_inclusive_rev)) 5843 || ((! is_rollback) && (rev < most_inclusive_rev))) 5844 most_inclusive_rev = rev; 5845 } 5846 } 5847 return most_inclusive_rev; 5848} 5849 5850 5851/* If first item in each child of CHILDREN_WITH_MERGEINFO's 5852 remaining_ranges is inclusive of END_REV, Slice the first range in 5853 to two at END_REV. All the allocations are persistent and allocated 5854 from POOL. */ 5855static void 5856slice_remaining_ranges(apr_array_header_t *children_with_mergeinfo, 5857 svn_boolean_t is_rollback, svn_revnum_t end_rev, 5858 apr_pool_t *pool) 5859{ 5860 int i; 5861 for (i = 0; i < children_with_mergeinfo->nelts; i++) 5862 { 5863 svn_client__merge_path_t *child = 5864 APR_ARRAY_IDX(children_with_mergeinfo, i, 5865 svn_client__merge_path_t *); 5866 if (!child || child->absent) 5867 continue; 5868 if (child->remaining_ranges->nelts > 0) 5869 { 5870 svn_merge_range_t *range = APR_ARRAY_IDX(child->remaining_ranges, 0, 5871 svn_merge_range_t *); 5872 if ((is_rollback && (range->start > end_rev) 5873 && (range->end < end_rev)) 5874 || (!is_rollback && (range->start < end_rev) 5875 && (range->end > end_rev))) 5876 { 5877 svn_merge_range_t *split_range1, *split_range2; 5878 5879 split_range1 = svn_merge_range_dup(range, pool); 5880 split_range2 = svn_merge_range_dup(range, pool); 5881 split_range1->end = end_rev; 5882 split_range2->start = end_rev; 5883 APR_ARRAY_IDX(child->remaining_ranges, 0, 5884 svn_merge_range_t *) = split_range1; 5885 svn_sort__array_insert(&split_range2, child->remaining_ranges, 1); 5886 } 5887 } 5888 } 5889} 5890 5891/* Helper for do_directory_merge(). 5892 5893 For each child in CHILDREN_WITH_MERGEINFO remove the first remaining_ranges 5894 svn_merge_range_t *element of the child if that range has an end revision 5895 equal to REVISION. 5896 5897 If a range is removed from a child's remaining_ranges array, allocate the 5898 new remaining_ranges array in POOL. 5899 */ 5900static void 5901remove_first_range_from_remaining_ranges(svn_revnum_t revision, 5902 apr_array_header_t 5903 *children_with_mergeinfo, 5904 apr_pool_t *pool) 5905{ 5906 int i; 5907 5908 for (i = 0; i < children_with_mergeinfo->nelts; i++) 5909 { 5910 svn_client__merge_path_t *child = 5911 APR_ARRAY_IDX(children_with_mergeinfo, i, 5912 svn_client__merge_path_t *); 5913 if (!child || child->absent) 5914 continue; 5915 if (child->remaining_ranges->nelts > 0) 5916 { 5917 svn_merge_range_t *first_range = 5918 APR_ARRAY_IDX(child->remaining_ranges, 0, svn_merge_range_t *); 5919 if (first_range->end == revision) 5920 { 5921 svn_sort__array_delete(child->remaining_ranges, 0, 1); 5922 } 5923 } 5924 } 5925} 5926 5927/* Get a file's content and properties from the repository. 5928 Set *FILENAME to the local path to a new temporary file holding its text, 5929 and set *PROPS to a new hash of its properties. 5930 5931 RA_SESSION is a session open to the correct repository, which will be 5932 temporarily reparented to the URL of the file itself. LOCATION is the 5933 repository location of the file. 5934 5935 The resulting file and the return values live as long as RESULT_POOL, all 5936 other allocations occur in SCRATCH_POOL. 5937*/ 5938static svn_error_t * 5939single_file_merge_get_file(const char **filename, 5940 apr_hash_t **props, 5941 svn_ra_session_t *ra_session, 5942 const svn_client__pathrev_t *location, 5943 const char *wc_target, 5944 apr_pool_t *result_pool, 5945 apr_pool_t *scratch_pool) 5946{ 5947 svn_stream_t *stream; 5948 const char *old_sess_url; 5949 svn_error_t *err; 5950 5951 SVN_ERR(svn_stream_open_unique(&stream, filename, NULL, 5952 svn_io_file_del_on_pool_cleanup, 5953 result_pool, scratch_pool)); 5954 5955 SVN_ERR(svn_client__ensure_ra_session_url(&old_sess_url, ra_session, location->url, 5956 scratch_pool)); 5957 err = svn_ra_get_file(ra_session, "", location->rev, 5958 stream, NULL, props, scratch_pool); 5959 SVN_ERR(svn_error_compose_create( 5960 err, svn_ra_reparent(ra_session, old_sess_url, scratch_pool))); 5961 5962 return svn_error_trace(svn_stream_close(stream)); 5963} 5964 5965/* Compare two svn_client__merge_path_t elements **A and **B, given the 5966 addresses of pointers to them. Return an integer less than, equal to, or 5967 greater than zero if A sorts before, the same as, or after B, respectively. 5968 This is a helper for qsort() and bsearch() on an array of such elements. */ 5969static int 5970compare_merge_path_t_as_paths(const void *a, 5971 const void *b) 5972{ 5973 const svn_client__merge_path_t *child1 5974 = *((const svn_client__merge_path_t * const *) a); 5975 const svn_client__merge_path_t *child2 5976 = *((const svn_client__merge_path_t * const *) b); 5977 5978 return svn_path_compare_paths(child1->abspath, child2->abspath); 5979} 5980 5981/* Return a pointer to the element of CHILDREN_WITH_MERGEINFO whose path 5982 * is PATH, or return NULL if there is no such element. */ 5983static svn_client__merge_path_t * 5984get_child_with_mergeinfo(const apr_array_header_t *children_with_mergeinfo, 5985 const char *abspath) 5986{ 5987 svn_client__merge_path_t merge_path; 5988 svn_client__merge_path_t *key; 5989 svn_client__merge_path_t **pchild; 5990 5991 merge_path.abspath = abspath; 5992 key = &merge_path; 5993 pchild = bsearch(&key, children_with_mergeinfo->elts, 5994 children_with_mergeinfo->nelts, 5995 children_with_mergeinfo->elt_size, 5996 compare_merge_path_t_as_paths); 5997 return pchild ? *pchild : NULL; 5998} 5999 6000/* Insert a deep copy of INSERT_ELEMENT into the CHILDREN_WITH_MERGEINFO 6001 array at its correct position. Allocate the new storage in POOL. 6002 CHILDREN_WITH_MERGEINFO is a depth first sorted array of 6003 (svn_client__merge_path_t *). 6004 6005 ### Most callers don't need this to deep-copy the new element. 6006 ### It may be more efficient for some callers to insert a bunch of items 6007 out of order and then sort afterwards. (One caller is doing a qsort 6008 after calling this anyway.) 6009 */ 6010static void 6011insert_child_to_merge(apr_array_header_t *children_with_mergeinfo, 6012 const svn_client__merge_path_t *insert_element, 6013 apr_pool_t *pool) 6014{ 6015 int insert_index; 6016 const svn_client__merge_path_t *new_element; 6017 6018 /* Find where to insert the new element */ 6019 insert_index = 6020 svn_sort__bsearch_lower_bound(&insert_element, children_with_mergeinfo, 6021 compare_merge_path_t_as_paths); 6022 6023 new_element = svn_client__merge_path_dup(insert_element, pool); 6024 svn_sort__array_insert(&new_element, children_with_mergeinfo, insert_index); 6025} 6026 6027/* Helper for get_mergeinfo_paths(). 6028 6029 CHILDREN_WITH_MERGEINFO, DEPTH, and POOL are 6030 all cascaded from the arguments of the same name to get_mergeinfo_paths(). 6031 6032 TARGET is the merge target. 6033 6034 *CHILD is the element in in CHILDREN_WITH_MERGEINFO that 6035 get_mergeinfo_paths() is iterating over and *CURR_INDEX is index for 6036 *CHILD. 6037 6038 If CHILD->ABSPATH is equal to MERGE_CMD_BATON->target->abspath do nothing. 6039 Else if CHILD->ABSPATH is switched or absent then make sure its immediate 6040 (as opposed to nearest) parent in CHILDREN_WITH_MERGEINFO is marked as 6041 missing a child. If the immediate parent does not exist in 6042 CHILDREN_WITH_MERGEINFO then create it (and increment *CURR_INDEX so that 6043 caller doesn't process the inserted element). Also ensure that 6044 CHILD->ABSPATH's siblings which are not already present in 6045 CHILDREN_WITH_MERGEINFO are also added to the array, limited by DEPTH 6046 (e.g. don't add directory siblings of a switched file). 6047 Use POOL for temporary allocations only, any new CHILDREN_WITH_MERGEINFO 6048 elements are allocated in POOL. */ 6049static svn_error_t * 6050insert_parent_and_sibs_of_sw_absent_del_subtree( 6051 apr_array_header_t *children_with_mergeinfo, 6052 const merge_target_t *target, 6053 int *curr_index, 6054 svn_client__merge_path_t *child, 6055 svn_depth_t depth, 6056 svn_client_ctx_t *ctx, 6057 apr_pool_t *pool) 6058{ 6059 svn_client__merge_path_t *parent; 6060 const char *parent_abspath; 6061 apr_pool_t *iterpool; 6062 const apr_array_header_t *children; 6063 int i; 6064 6065 if (!(child->absent 6066 || (child->switched 6067 && strcmp(target->abspath, 6068 child->abspath) != 0))) 6069 return SVN_NO_ERROR; 6070 6071 parent_abspath = svn_dirent_dirname(child->abspath, pool); 6072 parent = get_child_with_mergeinfo(children_with_mergeinfo, parent_abspath); 6073 if (parent) 6074 { 6075 parent->missing_child = child->absent; 6076 parent->switched_child = child->switched; 6077 } 6078 else 6079 { 6080 /* Create a new element to insert into CHILDREN_WITH_MERGEINFO. */ 6081 parent = svn_client__merge_path_create(parent_abspath, pool); 6082 parent->missing_child = child->absent; 6083 parent->switched_child = child->switched; 6084 /* Insert PARENT into CHILDREN_WITH_MERGEINFO. */ 6085 insert_child_to_merge(children_with_mergeinfo, parent, pool); 6086 /* Increment for loop index so we don't process the inserted element. */ 6087 (*curr_index)++; 6088 } /*(parent == NULL) */ 6089 6090 /* Add all of PARENT's non-missing children that are not already present.*/ 6091 SVN_ERR(svn_wc__node_get_children(&children, ctx->wc_ctx, 6092 parent_abspath, FALSE, pool, pool)); 6093 iterpool = svn_pool_create(pool); 6094 for (i = 0; i < children->nelts; i++) 6095 { 6096 const char *child_abspath = APR_ARRAY_IDX(children, i, const char *); 6097 svn_client__merge_path_t *sibling_of_missing; 6098 6099 svn_pool_clear(iterpool); 6100 6101 /* Does this child already exist in CHILDREN_WITH_MERGEINFO? */ 6102 sibling_of_missing = get_child_with_mergeinfo(children_with_mergeinfo, 6103 child_abspath); 6104 /* Create the missing child and insert it into CHILDREN_WITH_MERGEINFO.*/ 6105 if (!sibling_of_missing) 6106 { 6107 /* Don't add directory children if DEPTH is svn_depth_files. */ 6108 if (depth == svn_depth_files) 6109 { 6110 svn_node_kind_t child_kind; 6111 6112 SVN_ERR(svn_wc_read_kind2(&child_kind, 6113 ctx->wc_ctx, child_abspath, 6114 FALSE, FALSE, iterpool)); 6115 if (child_kind != svn_node_file) 6116 continue; 6117 } 6118 6119 sibling_of_missing = svn_client__merge_path_create(child_abspath, 6120 pool); 6121 insert_child_to_merge(children_with_mergeinfo, sibling_of_missing, 6122 pool); 6123 } 6124 } 6125 6126 svn_pool_destroy(iterpool); 6127 6128 return SVN_NO_ERROR; 6129} 6130 6131/* pre_merge_status_cb's baton */ 6132struct pre_merge_status_baton_t 6133{ 6134 svn_wc_context_t *wc_ctx; 6135 6136 /* const char *absolute_wc_path to svn_depth_t * mapping for depths 6137 of empty, immediates, and files. */ 6138 apr_hash_t *shallow_subtrees; 6139 6140 /* const char *absolute_wc_path to the same, for all paths missing 6141 from the working copy. */ 6142 apr_hash_t *missing_subtrees; 6143 6144 /* const char *absolute_wc_path const char * repos relative path, describing 6145 the root of each switched subtree in the working copy and the repository 6146 relative path it is switched to. */ 6147 apr_hash_t *switched_subtrees; 6148 6149 /* A pool to allocate additions to the above hashes in. */ 6150 apr_pool_t *pool; 6151}; 6152 6153/* A svn_wc_status_func4_t callback used by get_mergeinfo_paths to gather 6154 all switched, depth filtered and missing subtrees under a merge target. 6155 6156 Note that this doesn't see server and user excluded trees. */ 6157static svn_error_t * 6158pre_merge_status_cb(void *baton, 6159 const char *local_abspath, 6160 const svn_wc_status3_t *status, 6161 apr_pool_t *scratch_pool) 6162{ 6163 struct pre_merge_status_baton_t *pmsb = baton; 6164 6165 if (status->switched && !status->file_external) 6166 { 6167 store_path(pmsb->switched_subtrees, local_abspath); 6168 } 6169 6170 if (status->depth == svn_depth_empty 6171 || status->depth == svn_depth_files) 6172 { 6173 const char *dup_abspath; 6174 svn_depth_t *depth = apr_pmemdup(pmsb->pool, &status->depth, 6175 sizeof *depth); 6176 6177 dup_abspath = apr_pstrdup(pmsb->pool, local_abspath); 6178 6179 svn_hash_sets(pmsb->shallow_subtrees, dup_abspath, depth); 6180 } 6181 6182 if (status->node_status == svn_wc_status_missing) 6183 { 6184 svn_boolean_t new_missing_root = TRUE; 6185 apr_hash_index_t *hi; 6186 6187 for (hi = apr_hash_first(scratch_pool, pmsb->missing_subtrees); 6188 hi; 6189 hi = apr_hash_next(hi)) 6190 { 6191 const char *missing_root_path = svn__apr_hash_index_key(hi); 6192 6193 if (svn_dirent_is_ancestor(missing_root_path, 6194 local_abspath)) 6195 { 6196 new_missing_root = FALSE; 6197 break; 6198 } 6199 } 6200 6201 if (new_missing_root) 6202 store_path(pmsb->missing_subtrees, local_abspath); 6203 } 6204 6205 return SVN_NO_ERROR; 6206} 6207 6208/* Find all the subtrees in the working copy tree rooted at TARGET_ABSPATH 6209 * that have explicit mergeinfo. 6210 * Set *SUBTREES_WITH_MERGEINFO to a hash mapping (const char *) absolute 6211 * WC path to (svn_mergeinfo_t *) mergeinfo. 6212 * 6213 * ### Is this function equivalent to: 6214 * 6215 * svn_client__get_wc_mergeinfo_catalog( 6216 * subtrees_with_mergeinfo, inherited=NULL, include_descendants=TRUE, 6217 * svn_mergeinfo_explicit, target_abspath, limit_path=NULL, 6218 * walked_path=NULL, ignore_invalid_mergeinfo=FALSE, ...) 6219 * 6220 * except for the catalog keys being abspaths instead of repo-relpaths? 6221 */ 6222static svn_error_t * 6223get_wc_explicit_mergeinfo_catalog(apr_hash_t **subtrees_with_mergeinfo, 6224 const char *target_abspath, 6225 svn_depth_t depth, 6226 svn_client_ctx_t *ctx, 6227 apr_pool_t *result_pool, 6228 apr_pool_t *scratch_pool) 6229{ 6230 svn_opt_revision_t working_revision = { svn_opt_revision_working, { 0 } }; 6231 apr_pool_t *iterpool = svn_pool_create(scratch_pool); 6232 apr_hash_index_t *hi; 6233 apr_hash_t *externals; 6234 6235 SVN_ERR(svn_client_propget5(subtrees_with_mergeinfo, NULL, 6236 SVN_PROP_MERGEINFO, target_abspath, 6237 &working_revision, &working_revision, NULL, 6238 depth, NULL, ctx, result_pool, scratch_pool)); 6239 6240 SVN_ERR(svn_wc__externals_defined_below(&externals, ctx->wc_ctx, 6241 target_abspath, scratch_pool, 6242 scratch_pool)); 6243 6244 /* Convert property values to svn_mergeinfo_t. */ 6245 for (hi = apr_hash_first(scratch_pool, *subtrees_with_mergeinfo); 6246 hi; 6247 hi = apr_hash_next(hi)) 6248 { 6249 const char *wc_path = svn__apr_hash_index_key(hi); 6250 svn_string_t *mergeinfo_string = svn__apr_hash_index_val(hi); 6251 svn_mergeinfo_t mergeinfo; 6252 svn_error_t *err; 6253 6254 /* svn_client_propget5 picks up file externals with 6255 mergeinfo, but we don't want those. */ 6256 if (svn_hash_gets(externals, wc_path)) 6257 { 6258 svn_hash_sets(*subtrees_with_mergeinfo, wc_path, NULL); 6259 continue; 6260 } 6261 6262 svn_pool_clear(iterpool); 6263 6264 err = svn_mergeinfo_parse(&mergeinfo, mergeinfo_string->data, 6265 result_pool); 6266 if (err) 6267 { 6268 if (err->apr_err == SVN_ERR_MERGEINFO_PARSE_ERROR) 6269 { 6270 err = svn_error_createf( 6271 SVN_ERR_CLIENT_INVALID_MERGEINFO_NO_MERGETRACKING, err, 6272 _("Invalid mergeinfo detected on '%s', " 6273 "merge tracking not possible"), 6274 svn_dirent_local_style(wc_path, scratch_pool)); 6275 } 6276 return svn_error_trace(err); 6277 } 6278 svn_hash_sets(*subtrees_with_mergeinfo, wc_path, mergeinfo); 6279 } 6280 svn_pool_destroy(iterpool); 6281 6282 return SVN_NO_ERROR; 6283} 6284 6285/* Helper for do_directory_merge() when performing merge-tracking aware 6286 merges. 6287 6288 Walk of the working copy tree rooted at TARGET->abspath to 6289 depth DEPTH. Create an svn_client__merge_path_t * for any path which meets 6290 one or more of the following criteria: 6291 6292 1) Path has working svn:mergeinfo. 6293 2) Path is switched. 6294 3) Path is a subtree of the merge target (i.e. is not equal to 6295 TARGET->abspath) and has no mergeinfo of its own but 6296 its immediate parent has mergeinfo with non-inheritable ranges. If 6297 this isn't a dry-run and the merge is between differences in the same 6298 repository, then this function will set working mergeinfo on the path 6299 equal to the mergeinfo inheritable from its parent. 6300 4) Path has an immediate child (or children) missing from the WC because 6301 the child is switched or absent from the WC, or due to a sparse 6302 checkout. 6303 5) Path has a sibling (or siblings) missing from the WC because the 6304 sibling is switched, absent, scheduled for deletion, or missing due to 6305 a sparse checkout. 6306 6) Path is absent from disk due to an authz restriction. 6307 7) Path is equal to TARGET->abspath. 6308 8) Path is an immediate *directory* child of 6309 TARGET->abspath and DEPTH is svn_depth_immediates. 6310 9) Path is an immediate *file* child of TARGET->abspath 6311 and DEPTH is svn_depth_files. 6312 10) Path is at a depth of 'empty' or 'files'. 6313 11) Path is missing from disk (e.g. due to an OS-level deletion). 6314 6315 If subtrees within the requested DEPTH are unexpectedly missing disk, 6316 then raise SVN_ERR_CLIENT_NOT_READY_TO_MERGE. 6317 6318 Store the svn_client__merge_path_t *'s in *CHILDREN_WITH_MERGEINFO in 6319 depth-first order based on the svn_client__merge_path_t *s path member as 6320 sorted by svn_path_compare_paths(). Set the remaining_ranges field of each 6321 element to NULL. 6322 6323 Note: Since the walk is rooted at TARGET->abspath, the 6324 latter is guaranteed to be in *CHILDREN_WITH_MERGEINFO and due to the 6325 depth-first ordering it is guaranteed to be the first element in 6326 *CHILDREN_WITH_MERGEINFO. 6327 6328 MERGE_CMD_BATON is cascaded from the argument of the same name in 6329 do_directory_merge(). 6330*/ 6331static svn_error_t * 6332get_mergeinfo_paths(apr_array_header_t *children_with_mergeinfo, 6333 const merge_target_t *target, 6334 svn_depth_t depth, 6335 svn_boolean_t dry_run, 6336 svn_boolean_t same_repos, 6337 svn_client_ctx_t *ctx, 6338 apr_pool_t *result_pool, 6339 apr_pool_t *scratch_pool) 6340{ 6341 int i; 6342 apr_pool_t *iterpool = svn_pool_create(scratch_pool); 6343 apr_hash_t *subtrees_with_mergeinfo; 6344 apr_hash_t *excluded_subtrees; 6345 apr_hash_t *switched_subtrees; 6346 apr_hash_t *shallow_subtrees; 6347 apr_hash_t *missing_subtrees; 6348 struct pre_merge_status_baton_t pre_merge_status_baton; 6349 6350 /* Case 1: Subtrees with explicit mergeinfo. */ 6351 SVN_ERR(get_wc_explicit_mergeinfo_catalog(&subtrees_with_mergeinfo, 6352 target->abspath, 6353 depth, ctx, 6354 result_pool, scratch_pool)); 6355 if (subtrees_with_mergeinfo) 6356 { 6357 apr_hash_index_t *hi; 6358 6359 for (hi = apr_hash_first(scratch_pool, subtrees_with_mergeinfo); 6360 hi; 6361 hi = apr_hash_next(hi)) 6362 { 6363 const char *wc_path = svn__apr_hash_index_key(hi); 6364 svn_mergeinfo_t mergeinfo = svn__apr_hash_index_val(hi); 6365 svn_client__merge_path_t *mergeinfo_child = 6366 svn_client__merge_path_create(wc_path, result_pool); 6367 6368 svn_pool_clear(iterpool); 6369 6370 /* Stash this child's pre-existing mergeinfo. */ 6371 mergeinfo_child->pre_merge_mergeinfo = mergeinfo; 6372 6373 /* Note if this child has non-inheritable mergeinfo */ 6374 mergeinfo_child->has_noninheritable 6375 = svn_mergeinfo__is_noninheritable( 6376 mergeinfo_child->pre_merge_mergeinfo, iterpool); 6377 6378 /* Append it. We'll sort below. */ 6379 APR_ARRAY_PUSH(children_with_mergeinfo, svn_client__merge_path_t *) 6380 = svn_client__merge_path_dup(mergeinfo_child, result_pool); 6381 } 6382 6383 /* Sort CHILDREN_WITH_MERGEINFO by each child's path (i.e. as per 6384 compare_merge_path_t_as_paths). Any subsequent insertions of new 6385 children with insert_child_to_merge() require this ordering. */ 6386 qsort(children_with_mergeinfo->elts, 6387 children_with_mergeinfo->nelts, 6388 children_with_mergeinfo->elt_size, 6389 compare_merge_path_t_as_paths); 6390 } 6391 6392 /* Case 2: Switched subtrees 6393 Case 10: Paths at depths of 'empty' or 'files' 6394 Case 11: Paths missing from disk */ 6395 pre_merge_status_baton.wc_ctx = ctx->wc_ctx; 6396 switched_subtrees = apr_hash_make(scratch_pool); 6397 pre_merge_status_baton.switched_subtrees = switched_subtrees; 6398 shallow_subtrees = apr_hash_make(scratch_pool); 6399 pre_merge_status_baton.shallow_subtrees = shallow_subtrees; 6400 missing_subtrees = apr_hash_make(scratch_pool); 6401 pre_merge_status_baton.missing_subtrees = missing_subtrees; 6402 pre_merge_status_baton.pool = scratch_pool; 6403 SVN_ERR(svn_wc_walk_status(ctx->wc_ctx, 6404 target->abspath, 6405 depth, 6406 TRUE /* get_all */, 6407 FALSE /* no_ignore */, 6408 TRUE /* ignore_text_mods */, 6409 NULL /* ingore_patterns */, 6410 pre_merge_status_cb, &pre_merge_status_baton, 6411 ctx->cancel_func, ctx->cancel_baton, 6412 scratch_pool)); 6413 6414 /* Issue #2915: Raise an error describing the roots of any missing 6415 subtrees, i.e. those that the WC thinks are on disk but have been 6416 removed outside of Subversion. */ 6417 if (apr_hash_count(missing_subtrees)) 6418 { 6419 apr_hash_index_t *hi; 6420 svn_stringbuf_t *missing_subtree_err_buf = 6421 svn_stringbuf_create(_("Merge tracking not allowed with missing " 6422 "subtrees; try restoring these items " 6423 "first:\n"), scratch_pool); 6424 6425 for (hi = apr_hash_first(scratch_pool, missing_subtrees); 6426 hi; 6427 hi = apr_hash_next(hi)) 6428 { 6429 svn_pool_clear(iterpool); 6430 svn_stringbuf_appendcstr(missing_subtree_err_buf, 6431 svn_dirent_local_style( 6432 svn__apr_hash_index_key(hi), iterpool)); 6433 svn_stringbuf_appendcstr(missing_subtree_err_buf, "\n"); 6434 } 6435 6436 return svn_error_create(SVN_ERR_CLIENT_NOT_READY_TO_MERGE, 6437 NULL, missing_subtree_err_buf->data); 6438 } 6439 6440 if (apr_hash_count(switched_subtrees)) 6441 { 6442 apr_hash_index_t *hi; 6443 6444 for (hi = apr_hash_first(scratch_pool, switched_subtrees); 6445 hi; 6446 hi = apr_hash_next(hi)) 6447 { 6448 const char *wc_path = svn__apr_hash_index_key(hi); 6449 svn_client__merge_path_t *child = get_child_with_mergeinfo( 6450 children_with_mergeinfo, wc_path); 6451 6452 if (child) 6453 { 6454 child->switched = TRUE; 6455 } 6456 else 6457 { 6458 svn_client__merge_path_t *switched_child = 6459 svn_client__merge_path_create(wc_path, result_pool); 6460 switched_child->switched = TRUE; 6461 insert_child_to_merge(children_with_mergeinfo, switched_child, 6462 result_pool); 6463 } 6464 } 6465 } 6466 6467 if (apr_hash_count(shallow_subtrees)) 6468 { 6469 apr_hash_index_t *hi; 6470 6471 for (hi = apr_hash_first(scratch_pool, shallow_subtrees); 6472 hi; 6473 hi = apr_hash_next(hi)) 6474 { 6475 svn_boolean_t new_shallow_child = FALSE; 6476 const char *wc_path = svn__apr_hash_index_key(hi); 6477 svn_depth_t *child_depth = svn__apr_hash_index_val(hi); 6478 svn_client__merge_path_t *shallow_child = get_child_with_mergeinfo( 6479 children_with_mergeinfo, wc_path); 6480 6481 if (shallow_child) 6482 { 6483 if (*child_depth == svn_depth_empty 6484 || *child_depth == svn_depth_files) 6485 shallow_child->missing_child = TRUE; 6486 } 6487 else 6488 { 6489 shallow_child = svn_client__merge_path_create(wc_path, 6490 result_pool); 6491 new_shallow_child = TRUE; 6492 6493 if (*child_depth == svn_depth_empty 6494 || *child_depth == svn_depth_files) 6495 shallow_child->missing_child = TRUE; 6496 } 6497 6498 /* A little trickery: If PATH doesn't have any mergeinfo or has 6499 only inheritable mergeinfo, we still describe it as having 6500 non-inheritable mergeinfo if it is missing a child due to 6501 a shallow depth. Why? Because the mergeinfo we'll add to PATH 6502 to describe the merge must be non-inheritable, so PATH's missing 6503 children don't inherit it. Marking these PATHs as non- 6504 inheritable allows the logic for case 3 to properly account 6505 for PATH's children. */ 6506 if (!shallow_child->has_noninheritable 6507 && (*child_depth == svn_depth_empty 6508 || *child_depth == svn_depth_files)) 6509 { 6510 shallow_child->has_noninheritable = TRUE; 6511 } 6512 6513 if (new_shallow_child) 6514 insert_child_to_merge(children_with_mergeinfo, shallow_child, 6515 result_pool); 6516 } 6517 } 6518 6519 /* Case 6: Paths absent from disk due to server or user exclusion. */ 6520 SVN_ERR(svn_wc__get_excluded_subtrees(&excluded_subtrees, 6521 ctx->wc_ctx, target->abspath, 6522 result_pool, scratch_pool)); 6523 if (excluded_subtrees) 6524 { 6525 apr_hash_index_t *hi; 6526 6527 for (hi = apr_hash_first(scratch_pool, excluded_subtrees); 6528 hi; 6529 hi = apr_hash_next(hi)) 6530 { 6531 const char *wc_path = svn__apr_hash_index_key(hi); 6532 svn_client__merge_path_t *child = get_child_with_mergeinfo( 6533 children_with_mergeinfo, wc_path); 6534 6535 if (child) 6536 { 6537 child->absent = TRUE; 6538 } 6539 else 6540 { 6541 svn_client__merge_path_t *absent_child = 6542 svn_client__merge_path_create(wc_path, result_pool); 6543 absent_child->absent = TRUE; 6544 insert_child_to_merge(children_with_mergeinfo, absent_child, 6545 result_pool); 6546 } 6547 } 6548 } 6549 6550 /* Case 7: The merge target MERGE_CMD_BATON->target->abspath is always 6551 present. */ 6552 if (!get_child_with_mergeinfo(children_with_mergeinfo, 6553 target->abspath)) 6554 { 6555 svn_client__merge_path_t *target_child = 6556 svn_client__merge_path_create(target->abspath, 6557 result_pool); 6558 insert_child_to_merge(children_with_mergeinfo, target_child, 6559 result_pool); 6560 } 6561 6562 /* Case 8: Path is an immediate *directory* child of 6563 MERGE_CMD_BATON->target->abspath and DEPTH is svn_depth_immediates. 6564 6565 Case 9: Path is an immediate *file* child of 6566 MERGE_CMD_BATON->target->abspath and DEPTH is svn_depth_files. */ 6567 if (depth == svn_depth_immediates || depth == svn_depth_files) 6568 { 6569 int j; 6570 const apr_array_header_t *immediate_children; 6571 6572 SVN_ERR(svn_wc__node_get_children_of_working_node( 6573 &immediate_children, ctx->wc_ctx, 6574 target->abspath, FALSE, scratch_pool, scratch_pool)); 6575 6576 for (j = 0; j < immediate_children->nelts; j++) 6577 { 6578 const char *immediate_child_abspath = 6579 APR_ARRAY_IDX(immediate_children, j, const char *); 6580 svn_node_kind_t immediate_child_kind; 6581 6582 svn_pool_clear(iterpool); 6583 SVN_ERR(svn_wc_read_kind2(&immediate_child_kind, 6584 ctx->wc_ctx, immediate_child_abspath, 6585 FALSE, FALSE, iterpool)); 6586 if ((immediate_child_kind == svn_node_dir 6587 && depth == svn_depth_immediates) 6588 || (immediate_child_kind == svn_node_file 6589 && depth == svn_depth_files)) 6590 { 6591 if (!get_child_with_mergeinfo(children_with_mergeinfo, 6592 immediate_child_abspath)) 6593 { 6594 svn_client__merge_path_t *immediate_child = 6595 svn_client__merge_path_create(immediate_child_abspath, 6596 result_pool); 6597 6598 if (immediate_child_kind == svn_node_dir 6599 && depth == svn_depth_immediates) 6600 immediate_child->immediate_child_dir = TRUE; 6601 6602 insert_child_to_merge(children_with_mergeinfo, 6603 immediate_child, result_pool); 6604 } 6605 } 6606 } 6607 } 6608 6609 /* If DEPTH isn't empty then cover cases 3), 4), and 5), possibly adding 6610 elements to CHILDREN_WITH_MERGEINFO. */ 6611 if (depth <= svn_depth_empty) 6612 return SVN_NO_ERROR; 6613 6614 for (i = 0; i < children_with_mergeinfo->nelts; i++) 6615 { 6616 svn_client__merge_path_t *child = 6617 APR_ARRAY_IDX(children_with_mergeinfo, i, 6618 svn_client__merge_path_t *); 6619 svn_pool_clear(iterpool); 6620 6621 /* Case 3) Where merging to a path with a switched child the path 6622 gets non-inheritable mergeinfo for the merge range performed and 6623 the child gets its own set of mergeinfo. If the switched child 6624 later "returns", e.g. a switched path is unswitched, the child 6625 may not have any explicit mergeinfo. If the initial merge is 6626 repeated we don't want to repeat the merge for the path, but we 6627 do want to repeat it for the previously switched child. To 6628 ensure this we check if all of CHILD's non-missing children have 6629 explicit mergeinfo (they should already be present in 6630 CHILDREN_WITH_MERGEINFO if they do). If not, 6631 add the children without mergeinfo to CHILDREN_WITH_MERGEINFO so 6632 do_directory_merge() will merge them independently. 6633 6634 But that's not enough! Since do_directory_merge() performs 6635 the merges on the paths in CHILDREN_WITH_MERGEINFO in a depth 6636 first manner it will merge the previously switched path's parent 6637 first. As part of this merge it will update the parent's 6638 previously non-inheritable mergeinfo and make it inheritable 6639 (since it notices the path has no missing children), then when 6640 do_directory_merge() finally merges the previously missing 6641 child it needs to get mergeinfo from the child's nearest 6642 ancestor, but since do_directory_merge() already tweaked that 6643 mergeinfo, removing the non-inheritable flag, it appears that the 6644 child already has been merged to. To prevent this we set 6645 override mergeinfo on the child now, before any merging is done, 6646 so it has explicit mergeinfo that reflects only CHILD's 6647 inheritable mergeinfo. */ 6648 6649 /* If depth is immediates or files then don't add new children if 6650 CHILD is a subtree of the merge target; those children are below 6651 the operational depth of the merge. */ 6652 if (child->has_noninheritable 6653 && (i == 0 || depth == svn_depth_infinity)) 6654 { 6655 const apr_array_header_t *children; 6656 int j; 6657 6658 SVN_ERR(svn_wc__node_get_children(&children, 6659 ctx->wc_ctx, 6660 child->abspath, FALSE, 6661 iterpool, iterpool)); 6662 for (j = 0; j < children->nelts; j++) 6663 { 6664 svn_client__merge_path_t *child_of_noninheritable; 6665 const char *child_abspath = APR_ARRAY_IDX(children, j, 6666 const char*); 6667 6668 /* Does this child already exist in CHILDREN_WITH_MERGEINFO? 6669 If not, create it and insert it into 6670 CHILDREN_WITH_MERGEINFO and set override mergeinfo on 6671 it. */ 6672 child_of_noninheritable = 6673 get_child_with_mergeinfo(children_with_mergeinfo, 6674 child_abspath); 6675 if (!child_of_noninheritable) 6676 { 6677 /* Don't add directory children if DEPTH 6678 is svn_depth_files. */ 6679 if (depth == svn_depth_files) 6680 { 6681 svn_node_kind_t child_kind; 6682 SVN_ERR(svn_wc_read_kind2(&child_kind, 6683 ctx->wc_ctx, child_abspath, 6684 FALSE, FALSE, iterpool)); 6685 if (child_kind != svn_node_file) 6686 continue; 6687 } 6688 /* else DEPTH is infinity or immediates so we want both 6689 directory and file children. */ 6690 6691 child_of_noninheritable = 6692 svn_client__merge_path_create(child_abspath, result_pool); 6693 child_of_noninheritable->child_of_noninheritable = TRUE; 6694 insert_child_to_merge(children_with_mergeinfo, 6695 child_of_noninheritable, 6696 result_pool); 6697 if (!dry_run && same_repos) 6698 { 6699 svn_mergeinfo_t mergeinfo; 6700 6701 SVN_ERR(svn_client__get_wc_mergeinfo( 6702 &mergeinfo, NULL, 6703 svn_mergeinfo_nearest_ancestor, 6704 child_of_noninheritable->abspath, 6705 target->abspath, NULL, FALSE, 6706 ctx, iterpool, iterpool)); 6707 6708 SVN_ERR(svn_client__record_wc_mergeinfo( 6709 child_of_noninheritable->abspath, mergeinfo, 6710 FALSE, ctx, iterpool)); 6711 } 6712 } 6713 } 6714 } 6715 /* Case 4 and 5 are handled by the following function. */ 6716 SVN_ERR(insert_parent_and_sibs_of_sw_absent_del_subtree( 6717 children_with_mergeinfo, target, &i, child, 6718 depth, ctx, result_pool)); 6719 } /* i < children_with_mergeinfo->nelts */ 6720 svn_pool_destroy(iterpool); 6721 6722 return SVN_NO_ERROR; 6723} 6724 6725 6726/* Implements the svn_log_entry_receiver_t interface. 6727 * 6728 * BATON is an 'apr_array_header_t *' array of 'svn_revnum_t'. 6729 * Push a copy of LOG_ENTRY->revision onto BATON. Thus, a 6730 * series of invocations of this callback accumulates the 6731 * corresponding set of revisions into BATON. 6732 */ 6733static svn_error_t * 6734log_changed_revs(void *baton, 6735 svn_log_entry_t *log_entry, 6736 apr_pool_t *pool) 6737{ 6738 apr_array_header_t *revs = baton; 6739 6740 APR_ARRAY_PUSH(revs, svn_revnum_t) = log_entry->revision; 6741 return SVN_NO_ERROR; 6742} 6743 6744 6745/* Set *MIN_REV_P to the oldest and *MAX_REV_P to the youngest start or end 6746 * revision occurring in RANGELIST, or to SVN_INVALID_REVNUM if RANGELIST 6747 * is empty. */ 6748static void 6749merge_range_find_extremes(svn_revnum_t *min_rev_p, 6750 svn_revnum_t *max_rev_p, 6751 const svn_rangelist_t *rangelist) 6752{ 6753 int i; 6754 6755 *min_rev_p = SVN_INVALID_REVNUM; 6756 *max_rev_p = SVN_INVALID_REVNUM; 6757 for (i = 0; i < rangelist->nelts; i++) 6758 { 6759 svn_merge_range_t *range 6760 = APR_ARRAY_IDX(rangelist, i, svn_merge_range_t *); 6761 svn_revnum_t range_min = MIN(range->start, range->end); 6762 svn_revnum_t range_max = MAX(range->start, range->end); 6763 6764 if ((! SVN_IS_VALID_REVNUM(*min_rev_p)) || (range_min < *min_rev_p)) 6765 *min_rev_p = range_min; 6766 if ((! SVN_IS_VALID_REVNUM(*max_rev_p)) || (range_max > *max_rev_p)) 6767 *max_rev_p = range_max; 6768 } 6769} 6770 6771/* Wrapper around svn_ra_get_log2(). Invoke RECEIVER with RECEIVER_BATON 6772 * on each commit from YOUNGEST_REV to OLDEST_REV in which TARGET_RELPATH 6773 * changed. TARGET_RELPATH is relative to RA_SESSION's URL. 6774 * Important: Revision properties are not retrieved by this function for 6775 * performance reasons. 6776 */ 6777static svn_error_t * 6778get_log(svn_ra_session_t *ra_session, 6779 const char *target_relpath, 6780 svn_revnum_t youngest_rev, 6781 svn_revnum_t oldest_rev, 6782 svn_boolean_t discover_changed_paths, 6783 svn_log_entry_receiver_t receiver, 6784 void *receiver_baton, 6785 apr_pool_t *pool) 6786{ 6787 apr_array_header_t *log_targets; 6788 apr_array_header_t *revprops; 6789 6790 log_targets = apr_array_make(pool, 1, sizeof(const char *)); 6791 APR_ARRAY_PUSH(log_targets, const char *) = target_relpath; 6792 6793 revprops = apr_array_make(pool, 0, sizeof(const char *)); 6794 6795 SVN_ERR(svn_ra_get_log2(ra_session, log_targets, youngest_rev, 6796 oldest_rev, 0 /* limit */, discover_changed_paths, 6797 FALSE /* strict_node_history */, 6798 FALSE /* include_merged_revisions */, 6799 revprops, receiver, receiver_baton, pool)); 6800 6801 return SVN_NO_ERROR; 6802} 6803 6804/* Set *OPERATIVE_RANGES_P to an array of svn_merge_range_t * merge 6805 range objects copied wholesale from RANGES which have the property 6806 that in some revision within that range the object identified by 6807 RA_SESSION was modified (if by "modified" we mean "'svn log' would 6808 return that revision). *OPERATIVE_RANGES_P is allocated from the 6809 same pool as RANGES, and the ranges within it are shared with 6810 RANGES, too. 6811 6812 *OPERATIVE_RANGES_P may be the same as RANGES (that is, the output 6813 parameter is set only after the input is no longer used). 6814 6815 Use POOL for temporary allocations. */ 6816static svn_error_t * 6817remove_noop_merge_ranges(svn_rangelist_t **operative_ranges_p, 6818 svn_ra_session_t *ra_session, 6819 const svn_rangelist_t *ranges, 6820 apr_pool_t *pool) 6821{ 6822 int i; 6823 svn_revnum_t oldest_rev, youngest_rev; 6824 apr_array_header_t *changed_revs = 6825 apr_array_make(pool, ranges->nelts, sizeof(svn_revnum_t)); 6826 svn_rangelist_t *operative_ranges = 6827 apr_array_make(ranges->pool, ranges->nelts, ranges->elt_size); 6828 6829 /* Find the revision extremes of the RANGES we have. */ 6830 merge_range_find_extremes(&oldest_rev, &youngest_rev, ranges); 6831 if (SVN_IS_VALID_REVNUM(oldest_rev)) 6832 oldest_rev++; /* make it inclusive */ 6833 6834 /* Get logs across those ranges, recording which revisions hold 6835 changes to our object's history. */ 6836 SVN_ERR(get_log(ra_session, "", youngest_rev, oldest_rev, FALSE, 6837 log_changed_revs, changed_revs, pool)); 6838 6839 /* Are there *any* changes? */ 6840 if (changed_revs->nelts) 6841 { 6842 /* Our list of changed revisions should be in youngest-to-oldest 6843 order. */ 6844 svn_revnum_t youngest_changed_rev 6845 = APR_ARRAY_IDX(changed_revs, 0, svn_revnum_t); 6846 svn_revnum_t oldest_changed_rev 6847 = APR_ARRAY_IDX(changed_revs, changed_revs->nelts - 1, svn_revnum_t); 6848 6849 /* Now, copy from RANGES to *OPERATIVE_RANGES, filtering out ranges 6850 that aren't operative (by virtue of not having any revisions 6851 represented in the CHANGED_REVS array). */ 6852 for (i = 0; i < ranges->nelts; i++) 6853 { 6854 svn_merge_range_t *range = APR_ARRAY_IDX(ranges, i, 6855 svn_merge_range_t *); 6856 svn_revnum_t range_min = MIN(range->start, range->end) + 1; 6857 svn_revnum_t range_max = MAX(range->start, range->end); 6858 int j; 6859 6860 /* If the merge range is entirely outside the range of changed 6861 revisions, we've no use for it. */ 6862 if ((range_min > youngest_changed_rev) 6863 || (range_max < oldest_changed_rev)) 6864 continue; 6865 6866 /* Walk through the changed_revs to see if any of them fall 6867 inside our current range. */ 6868 for (j = 0; j < changed_revs->nelts; j++) 6869 { 6870 svn_revnum_t changed_rev 6871 = APR_ARRAY_IDX(changed_revs, j, svn_revnum_t); 6872 if ((changed_rev >= range_min) && (changed_rev <= range_max)) 6873 { 6874 APR_ARRAY_PUSH(operative_ranges, svn_merge_range_t *) = 6875 range; 6876 break; 6877 } 6878 } 6879 } 6880 } 6881 6882 *operative_ranges_p = operative_ranges; 6883 return SVN_NO_ERROR; 6884} 6885 6886 6887/*-----------------------------------------------------------------------*/ 6888 6889/*** Merge Source Normalization ***/ 6890 6891/* qsort-compatible sort routine, rating merge_source_t * objects to 6892 be in descending (youngest-to-oldest) order based on their ->loc1->rev 6893 component. */ 6894static int 6895compare_merge_source_ts(const void *a, 6896 const void *b) 6897{ 6898 svn_revnum_t a_rev = (*(const merge_source_t *const *)a)->loc1->rev; 6899 svn_revnum_t b_rev = (*(const merge_source_t *const *)b)->loc1->rev; 6900 if (a_rev == b_rev) 6901 return 0; 6902 return a_rev < b_rev ? 1 : -1; 6903} 6904 6905/* Set *MERGE_SOURCE_TS_P to a list of merge sources generated by 6906 slicing history location SEGMENTS with a given requested merge 6907 RANGE. Use SOURCE_LOC for full source URL calculation. 6908 6909 Order the merge sources in *MERGE_SOURCE_TS_P from oldest to 6910 youngest. */ 6911static svn_error_t * 6912combine_range_with_segments(apr_array_header_t **merge_source_ts_p, 6913 const svn_merge_range_t *range, 6914 const apr_array_header_t *segments, 6915 const svn_client__pathrev_t *source_loc, 6916 apr_pool_t *pool) 6917{ 6918 apr_array_header_t *merge_source_ts = 6919 apr_array_make(pool, 1, sizeof(merge_source_t *)); 6920 svn_revnum_t minrev = MIN(range->start, range->end) + 1; 6921 svn_revnum_t maxrev = MAX(range->start, range->end); 6922 svn_boolean_t subtractive = (range->start > range->end); 6923 int i; 6924 6925 for (i = 0; i < segments->nelts; i++) 6926 { 6927 svn_location_segment_t *segment = 6928 APR_ARRAY_IDX(segments, i, svn_location_segment_t *); 6929 svn_client__pathrev_t *loc1, *loc2; 6930 merge_source_t *merge_source; 6931 const char *path1 = NULL; 6932 svn_revnum_t rev1; 6933 6934 /* If this segment doesn't overlap our range at all, or 6935 represents a gap, ignore it. */ 6936 if ((segment->range_end < minrev) 6937 || (segment->range_start > maxrev) 6938 || (! segment->path)) 6939 continue; 6940 6941 /* If our range spans a segment boundary, we have to point our 6942 merge_source_t's path1 to the path of the immediately older 6943 segment, else it points to the same location as its path2. */ 6944 rev1 = MAX(segment->range_start, minrev) - 1; 6945 if (minrev <= segment->range_start) 6946 { 6947 if (i > 0) 6948 { 6949 path1 = (APR_ARRAY_IDX(segments, i - 1, 6950 svn_location_segment_t *))->path; 6951 } 6952 /* If we've backed PATH1 up into a segment gap, let's back 6953 it up further still to the segment before the gap. We'll 6954 have to adjust rev1, too. */ 6955 if ((! path1) && (i > 1)) 6956 { 6957 path1 = (APR_ARRAY_IDX(segments, i - 2, 6958 svn_location_segment_t *))->path; 6959 rev1 = (APR_ARRAY_IDX(segments, i - 2, 6960 svn_location_segment_t *))->range_end; 6961 } 6962 } 6963 else 6964 { 6965 path1 = apr_pstrdup(pool, segment->path); 6966 } 6967 6968 /* If we don't have two valid paths, we won't know what to do 6969 when merging. This could happen if someone requested a merge 6970 where the source didn't exist in a particular revision or 6971 something. The merge code would probably bomb out anyway, so 6972 we'll just *not* create a merge source in this case. */ 6973 if (! (path1 && segment->path)) 6974 continue; 6975 6976 /* Build our merge source structure. */ 6977 loc1 = svn_client__pathrev_create_with_relpath( 6978 source_loc->repos_root_url, source_loc->repos_uuid, 6979 rev1, path1, pool); 6980 loc2 = svn_client__pathrev_create_with_relpath( 6981 source_loc->repos_root_url, source_loc->repos_uuid, 6982 MIN(segment->range_end, maxrev), segment->path, pool); 6983 /* If this is subtractive, reverse the whole calculation. */ 6984 if (subtractive) 6985 merge_source = merge_source_create(loc2, loc1, TRUE /* ancestral */, 6986 pool); 6987 else 6988 merge_source = merge_source_create(loc1, loc2, TRUE /* ancestral */, 6989 pool); 6990 6991 APR_ARRAY_PUSH(merge_source_ts, merge_source_t *) = merge_source; 6992 } 6993 6994 /* If this was a subtractive merge, and we created more than one 6995 merge source, we need to reverse the sort ordering of our sources. */ 6996 if (subtractive && (merge_source_ts->nelts > 1)) 6997 qsort(merge_source_ts->elts, merge_source_ts->nelts, 6998 merge_source_ts->elt_size, compare_merge_source_ts); 6999 7000 *merge_source_ts_p = merge_source_ts; 7001 return SVN_NO_ERROR; 7002} 7003 7004/* Similar to normalize_merge_sources() except the input MERGE_RANGE_TS is a 7005 * rangelist. 7006 */ 7007static svn_error_t * 7008normalize_merge_sources_internal(apr_array_header_t **merge_sources_p, 7009 const svn_client__pathrev_t *source_loc, 7010 const svn_rangelist_t *merge_range_ts, 7011 svn_ra_session_t *ra_session, 7012 svn_client_ctx_t *ctx, 7013 apr_pool_t *result_pool, 7014 apr_pool_t *scratch_pool) 7015{ 7016 svn_revnum_t source_peg_revnum = source_loc->rev; 7017 svn_revnum_t oldest_requested, youngest_requested; 7018 svn_revnum_t trim_revision = SVN_INVALID_REVNUM; 7019 apr_array_header_t *segments; 7020 int i; 7021 7022 /* Initialize our return variable. */ 7023 *merge_sources_p = apr_array_make(result_pool, 1, sizeof(merge_source_t *)); 7024 7025 /* No ranges to merge? No problem. */ 7026 if (merge_range_ts->nelts == 0) 7027 return SVN_NO_ERROR; 7028 7029 /* Find the extremes of the revisions across our set of ranges. */ 7030 merge_range_find_extremes(&oldest_requested, &youngest_requested, 7031 merge_range_ts); 7032 7033 /* ### FIXME: Our underlying APIs can't yet handle the case where 7034 the peg revision isn't the youngest of the three revisions. So 7035 we'll just verify that the source in the peg revision is related 7036 to the source in the youngest requested revision (which is 7037 all the underlying APIs would do in this case right now anyway). */ 7038 if (source_peg_revnum < youngest_requested) 7039 { 7040 svn_client__pathrev_t *start_loc; 7041 7042 SVN_ERR(svn_client__repos_location(&start_loc, 7043 ra_session, source_loc, 7044 youngest_requested, 7045 ctx, scratch_pool, scratch_pool)); 7046 source_peg_revnum = youngest_requested; 7047 } 7048 7049 /* Fetch the locations for our merge range span. */ 7050 SVN_ERR(svn_client__repos_location_segments(&segments, 7051 ra_session, source_loc->url, 7052 source_peg_revnum, 7053 youngest_requested, 7054 oldest_requested, 7055 ctx, result_pool)); 7056 7057 /* See if we fetched enough history to do the job. "Surely we did," 7058 you say. "After all, we covered the entire requested merge 7059 range." Yes, that's true, but if our first segment doesn't 7060 extend back to the oldest request revision, we've got a special 7061 case to deal with. Or if the first segment represents a gap, 7062 that's another special case. */ 7063 trim_revision = SVN_INVALID_REVNUM; 7064 if (segments->nelts) 7065 { 7066 svn_location_segment_t *first_segment = 7067 APR_ARRAY_IDX(segments, 0, svn_location_segment_t *); 7068 7069 /* If the first segment doesn't start with the OLDEST_REQUESTED 7070 revision, we'll need to pass a trim revision to our range 7071 cruncher. */ 7072 if (first_segment->range_start != oldest_requested) 7073 { 7074 trim_revision = first_segment->range_start; 7075 } 7076 7077 /* Else, if the first segment has no path (and therefore is a 7078 gap), then we'll fetch the copy source revision from the 7079 second segment (provided there is one, of course) and use it 7080 to prepend an extra pathful segment to our list. 7081 7082 ### We could avoid this bit entirely if we'd passed 7083 ### SVN_INVALID_REVNUM instead of OLDEST_REQUESTED to 7084 ### svn_client__repos_location_segments(), but that would 7085 ### really penalize clients hitting pre-1.5 repositories with 7086 ### the typical small merge range request (because of the 7087 ### lack of a node-origins cache in the repository). */ 7088 else if (! first_segment->path) 7089 { 7090 if (segments->nelts > 1) 7091 { 7092 svn_location_segment_t *second_segment = 7093 APR_ARRAY_IDX(segments, 1, svn_location_segment_t *); 7094 const char *segment_url; 7095 const char *original_repos_relpath; 7096 svn_revnum_t original_revision; 7097 svn_opt_revision_t range_start_rev; 7098 range_start_rev.kind = svn_opt_revision_number; 7099 range_start_rev.value.number = second_segment->range_start; 7100 7101 segment_url = svn_path_url_add_component2( 7102 source_loc->repos_root_url, second_segment->path, 7103 scratch_pool); 7104 SVN_ERR(svn_client__get_copy_source(&original_repos_relpath, 7105 &original_revision, 7106 segment_url, 7107 &range_start_rev, ctx, 7108 result_pool, scratch_pool)); 7109 /* Got copyfrom data? Fix up the first segment to cover 7110 back to COPYFROM_REV + 1, and then prepend a new 7111 segment covering just COPYFROM_REV. */ 7112 if (original_repos_relpath) 7113 { 7114 svn_location_segment_t *new_segment = 7115 apr_pcalloc(result_pool, sizeof(*new_segment)); 7116 7117 new_segment->path = original_repos_relpath; 7118 new_segment->range_start = original_revision; 7119 new_segment->range_end = original_revision; 7120 svn_sort__array_insert(&new_segment, segments, 0); 7121 } 7122 } 7123 } 7124 } 7125 7126 /* For each range in our requested range set, try to determine the 7127 path(s) associated with that range. */ 7128 for (i = 0; i < merge_range_ts->nelts; i++) 7129 { 7130 svn_merge_range_t *range = 7131 APR_ARRAY_IDX(merge_range_ts, i, svn_merge_range_t *); 7132 apr_array_header_t *merge_sources; 7133 7134 if (SVN_IS_VALID_REVNUM(trim_revision)) 7135 { 7136 /* If the range predates the trim revision, discard it. */ 7137 if (MAX(range->start, range->end) < trim_revision) 7138 continue; 7139 7140 /* If the range overlaps the trim revision, trim it. */ 7141 if (range->start < trim_revision) 7142 range->start = trim_revision; 7143 if (range->end < trim_revision) 7144 range->end = trim_revision; 7145 } 7146 7147 /* Copy the resulting merge sources into master list thereof. */ 7148 SVN_ERR(combine_range_with_segments(&merge_sources, range, 7149 segments, source_loc, 7150 result_pool)); 7151 apr_array_cat(*merge_sources_p, merge_sources); 7152 } 7153 7154 return SVN_NO_ERROR; 7155} 7156 7157/* Determine the normalized ranges to merge from a given line of history. 7158 7159 Calculate the result by intersecting the list of location segments at 7160 which SOURCE_LOC existed along its line of history with the requested 7161 revision ranges in RANGES_TO_MERGE. RANGES_TO_MERGE is an array of 7162 (svn_opt_revision_range_t *) revision ranges. Use SOURCE_PATH_OR_URL to 7163 resolve any WC-relative revision specifiers (such as 'base') in 7164 RANGES_TO_MERGE. 7165 7166 Set *MERGE_SOURCES_P to an array of merge_source_t * objects, each 7167 describing a normalized range of revisions to be merged from the line 7168 history of SOURCE_LOC. Order the objects from oldest to youngest. 7169 7170 RA_SESSION is an RA session open to the repository of SOURCE_LOC; it may 7171 be temporarily reparented within this function. Use RA_SESSION to find 7172 the location segments along the line of history of SOURCE_LOC. 7173 7174 Allocate MERGE_SOURCES_P and its contents in RESULT_POOL. 7175 7176 See `MERGEINFO MERGE SOURCE NORMALIZATION' for more on the 7177 background of this function. 7178*/ 7179static svn_error_t * 7180normalize_merge_sources(apr_array_header_t **merge_sources_p, 7181 const char *source_path_or_url, 7182 const svn_client__pathrev_t *source_loc, 7183 const apr_array_header_t *ranges_to_merge, 7184 svn_ra_session_t *ra_session, 7185 svn_client_ctx_t *ctx, 7186 apr_pool_t *result_pool, 7187 apr_pool_t *scratch_pool) 7188{ 7189 const char *source_abspath_or_url; 7190 svn_revnum_t youngest_rev = SVN_INVALID_REVNUM; 7191 svn_rangelist_t *merge_range_ts; 7192 int i; 7193 apr_pool_t *iterpool = svn_pool_create(scratch_pool); 7194 7195 if(!svn_path_is_url(source_path_or_url)) 7196 SVN_ERR(svn_dirent_get_absolute(&source_abspath_or_url, source_path_or_url, 7197 scratch_pool)); 7198 else 7199 source_abspath_or_url = source_path_or_url; 7200 7201 /* Create a list to hold svn_merge_range_t's. */ 7202 merge_range_ts = apr_array_make(scratch_pool, ranges_to_merge->nelts, 7203 sizeof(svn_merge_range_t *)); 7204 7205 for (i = 0; i < ranges_to_merge->nelts; i++) 7206 { 7207 svn_opt_revision_range_t *range 7208 = APR_ARRAY_IDX(ranges_to_merge, i, svn_opt_revision_range_t *); 7209 svn_merge_range_t mrange; 7210 7211 svn_pool_clear(iterpool); 7212 7213 /* Resolve revisions to real numbers, validating as we go. */ 7214 if ((range->start.kind == svn_opt_revision_unspecified) 7215 || (range->end.kind == svn_opt_revision_unspecified)) 7216 return svn_error_create(SVN_ERR_CLIENT_BAD_REVISION, NULL, 7217 _("Not all required revisions are specified")); 7218 7219 SVN_ERR(svn_client__get_revision_number(&mrange.start, &youngest_rev, 7220 ctx->wc_ctx, 7221 source_abspath_or_url, 7222 ra_session, &range->start, 7223 iterpool)); 7224 SVN_ERR(svn_client__get_revision_number(&mrange.end, &youngest_rev, 7225 ctx->wc_ctx, 7226 source_abspath_or_url, 7227 ra_session, &range->end, 7228 iterpool)); 7229 7230 /* If this isn't a no-op range... */ 7231 if (mrange.start != mrange.end) 7232 { 7233 /* ...then add it to the list. */ 7234 mrange.inheritable = TRUE; 7235 APR_ARRAY_PUSH(merge_range_ts, svn_merge_range_t *) 7236 = svn_merge_range_dup(&mrange, scratch_pool); 7237 } 7238 } 7239 7240 SVN_ERR(normalize_merge_sources_internal( 7241 merge_sources_p, source_loc, 7242 merge_range_ts, ra_session, ctx, result_pool, scratch_pool)); 7243 7244 svn_pool_destroy(iterpool); 7245 return SVN_NO_ERROR; 7246} 7247 7248 7249/*-----------------------------------------------------------------------*/ 7250 7251/*** Merge Workhorse Functions ***/ 7252 7253/* Helper for do_directory_merge() and do_file_merge() which filters out a 7254 path's own natural history from the mergeinfo describing a merge. 7255 7256 Given the natural history IMPLICIT_MERGEINFO of some wc merge target path, 7257 the repository-relative merge source path SOURCE_REL_PATH, and the 7258 requested merge range REQUESTED_RANGE from SOURCE_REL_PATH, remove any 7259 portion of REQUESTED_RANGE which is already described in 7260 IMPLICIT_MERGEINFO. Store the result in *FILTERED_RANGELIST. 7261 7262 This function only filters natural history for mergeinfo that will be 7263 *added* during a forward merge. Removing natural history from explicit 7264 mergeinfo is harmless. If REQUESTED_RANGE describes a reverse merge, 7265 then *FILTERED_RANGELIST is simply populated with one range described 7266 by REQUESTED_RANGE. *FILTERED_RANGELIST is never NULL. 7267 7268 Allocate *FILTERED_RANGELIST in POOL. */ 7269static svn_error_t * 7270filter_natural_history_from_mergeinfo(svn_rangelist_t **filtered_rangelist, 7271 const char *source_rel_path, 7272 svn_mergeinfo_t implicit_mergeinfo, 7273 svn_merge_range_t *requested_range, 7274 apr_pool_t *pool) 7275{ 7276 /* Make the REQUESTED_RANGE into a rangelist. */ 7277 svn_rangelist_t *requested_rangelist = 7278 svn_rangelist__initialize(requested_range->start, requested_range->end, 7279 requested_range->inheritable, pool); 7280 7281 *filtered_rangelist = NULL; 7282 7283 /* For forward merges: If the IMPLICIT_MERGEINFO already describes ranges 7284 associated with SOURCE_REL_PATH then filter those ranges out. */ 7285 if (implicit_mergeinfo 7286 && (requested_range->start < requested_range->end)) 7287 { 7288 svn_rangelist_t *implied_rangelist = 7289 svn_hash_gets(implicit_mergeinfo, source_rel_path); 7290 7291 if (implied_rangelist) 7292 SVN_ERR(svn_rangelist_remove(filtered_rangelist, 7293 implied_rangelist, 7294 requested_rangelist, 7295 FALSE, pool)); 7296 } 7297 7298 /* If no filtering was performed the filtered rangelist is 7299 simply the requested rangelist.*/ 7300 if (! (*filtered_rangelist)) 7301 *filtered_rangelist = requested_rangelist; 7302 7303 return SVN_NO_ERROR; 7304} 7305 7306/* Return a merge source representing the sub-range from START_REV to 7307 END_REV of SOURCE. SOURCE obeys the rules described in the 7308 'MERGEINFO MERGE SOURCE NORMALIZATION' comment at the top of this file. 7309 The younger of START_REV and END_REV is inclusive while the older is 7310 exclusive. 7311 7312 Allocate the result structure in POOL but leave the URLs in it as shallow 7313 copies of the URLs in SOURCE. 7314*/ 7315static merge_source_t * 7316subrange_source(const merge_source_t *source, 7317 svn_revnum_t start_rev, 7318 svn_revnum_t end_rev, 7319 apr_pool_t *pool) 7320{ 7321 svn_boolean_t is_rollback = (source->loc1->rev > source->loc2->rev); 7322 svn_boolean_t same_urls = (strcmp(source->loc1->url, source->loc2->url) == 0); 7323 svn_client__pathrev_t loc1 = *source->loc1; 7324 svn_client__pathrev_t loc2 = *source->loc2; 7325 7326 /* For this function we require that the input source is 'ancestral'. */ 7327 SVN_ERR_ASSERT_NO_RETURN(source->ancestral); 7328 SVN_ERR_ASSERT_NO_RETURN(start_rev != end_rev); 7329 7330 loc1.rev = start_rev; 7331 loc2.rev = end_rev; 7332 if (! same_urls) 7333 { 7334 if (is_rollback && (end_rev != source->loc2->rev)) 7335 { 7336 loc2.url = source->loc1->url; 7337 } 7338 if ((! is_rollback) && (start_rev != source->loc1->rev)) 7339 { 7340 loc1.url = source->loc2->url; 7341 } 7342 } 7343 return merge_source_create(&loc1, &loc2, source->ancestral, pool); 7344} 7345 7346/* The single-file, simplified version of do_directory_merge(), which see for 7347 parameter descriptions. 7348 7349 Additional parameters: 7350 7351 If SOURCES_RELATED is set, the "left" and "right" sides of SOURCE are 7352 historically related (ancestors, uncles, second 7353 cousins thrice removed, etc...). (This is used to simulate the 7354 history checks that the repository logic does in the directory case.) 7355 7356 If mergeinfo is being recorded to describe this merge, and RESULT_CATALOG 7357 is not NULL, then don't record the new mergeinfo on the TARGET_ABSPATH, 7358 but instead record it in RESULT_CATALOG, where the key is TARGET_ABSPATH 7359 and the value is the new mergeinfo for that path. Allocate additions 7360 to RESULT_CATALOG in pool which RESULT_CATALOG was created in. 7361 7362 CONFLICTED_RANGE is as documented for do_directory_merge(). 7363 7364 Note: MERGE_B->RA_SESSION1 must be associated with SOURCE->loc1->url and 7365 MERGE_B->RA_SESSION2 with SOURCE->loc2->url. 7366*/ 7367static svn_error_t * 7368do_file_merge(svn_mergeinfo_catalog_t result_catalog, 7369 single_range_conflict_report_t **conflict_report, 7370 const merge_source_t *source, 7371 const char *target_abspath, 7372 const svn_diff_tree_processor_t *processor, 7373 svn_boolean_t sources_related, 7374 svn_boolean_t squelch_mergeinfo_notifications, 7375 merge_cmd_baton_t *merge_b, 7376 apr_pool_t *result_pool, 7377 apr_pool_t *scratch_pool) 7378{ 7379 svn_rangelist_t *remaining_ranges; 7380 svn_client_ctx_t *ctx = merge_b->ctx; 7381 svn_merge_range_t range; 7382 svn_mergeinfo_t target_mergeinfo; 7383 svn_boolean_t inherited = FALSE; 7384 svn_boolean_t is_rollback = (source->loc1->rev > source->loc2->rev); 7385 const svn_client__pathrev_t *primary_src 7386 = is_rollback ? source->loc1 : source->loc2; 7387 svn_boolean_t honor_mergeinfo = HONOR_MERGEINFO(merge_b); 7388 svn_client__merge_path_t *merge_target = NULL; 7389 apr_pool_t *iterpool = svn_pool_create(scratch_pool); 7390 7391 SVN_ERR_ASSERT(svn_dirent_is_absolute(target_abspath)); 7392 7393 *conflict_report = NULL; 7394 7395 /* Note that this is a single-file merge. */ 7396 range.start = source->loc1->rev; 7397 range.end = source->loc2->rev; 7398 range.inheritable = TRUE; 7399 7400 merge_target = svn_client__merge_path_create(target_abspath, scratch_pool); 7401 7402 if (honor_mergeinfo) 7403 { 7404 svn_error_t *err; 7405 7406 /* Fetch mergeinfo. */ 7407 err = get_full_mergeinfo(&target_mergeinfo, 7408 &(merge_target->implicit_mergeinfo), 7409 &inherited, svn_mergeinfo_inherited, 7410 merge_b->ra_session1, target_abspath, 7411 MAX(source->loc1->rev, source->loc2->rev), 7412 MIN(source->loc1->rev, source->loc2->rev), 7413 ctx, scratch_pool, iterpool); 7414 7415 if (err) 7416 { 7417 if (err->apr_err == SVN_ERR_MERGEINFO_PARSE_ERROR) 7418 { 7419 err = svn_error_createf( 7420 SVN_ERR_CLIENT_INVALID_MERGEINFO_NO_MERGETRACKING, err, 7421 _("Invalid mergeinfo detected on merge target '%s', " 7422 "merge tracking not possible"), 7423 svn_dirent_local_style(target_abspath, scratch_pool)); 7424 } 7425 return svn_error_trace(err); 7426 } 7427 7428 /* Calculate remaining merges unless this is a record only merge. 7429 In that case the remaining range is the whole range described 7430 by SOURCE->rev1:rev2. */ 7431 if (!merge_b->record_only) 7432 { 7433 /* ### Bug? calculate_remaining_ranges() needs 'source' to adhere 7434 * to the requirements of 'MERGEINFO MERGE SOURCE NORMALIZATION' 7435 * here, but it doesn't appear to be guaranteed so. */ 7436 SVN_ERR(calculate_remaining_ranges(NULL, merge_target, 7437 source, 7438 target_mergeinfo, 7439 merge_b->implicit_src_gap, FALSE, 7440 merge_b->ra_session1, 7441 ctx, scratch_pool, 7442 iterpool)); 7443 remaining_ranges = merge_target->remaining_ranges; 7444 7445 /* We are honoring mergeinfo and this is not a simple record only 7446 merge which blindly records mergeinfo describing the merge of 7447 SOURCE->LOC1->URL@SOURCE->LOC1->REV through 7448 SOURCE->LOC2->URL@SOURCE->LOC2->REV. This means that the oldest 7449 and youngest revisions merged (as determined above by 7450 calculate_remaining_ranges) might differ from those described 7451 in SOURCE. To keep the '--- Merging *' notifications consistent 7452 with the '--- Recording mergeinfo *' notifications, we adjust 7453 RANGE to account for such changes. */ 7454 if (remaining_ranges->nelts) 7455 { 7456 svn_merge_range_t *adj_start_range = 7457 APR_ARRAY_IDX(remaining_ranges, 0, svn_merge_range_t *); 7458 svn_merge_range_t *adj_end_range = 7459 APR_ARRAY_IDX(remaining_ranges, remaining_ranges->nelts - 1, 7460 svn_merge_range_t *); 7461 range.start = adj_start_range->start; 7462 range.end = adj_end_range->end; 7463 } 7464 } 7465 } 7466 7467 /* The simple cases where our remaining range is SOURCE->rev1:rev2. */ 7468 if (!honor_mergeinfo || merge_b->record_only) 7469 { 7470 remaining_ranges = apr_array_make(scratch_pool, 1, sizeof(&range)); 7471 APR_ARRAY_PUSH(remaining_ranges, svn_merge_range_t *) = ⦥ 7472 } 7473 7474 if (!merge_b->record_only) 7475 { 7476 svn_rangelist_t *ranges_to_merge = apr_array_copy(scratch_pool, 7477 remaining_ranges); 7478 const char *target_relpath = ""; /* relative to root of merge */ 7479 7480 if (source->ancestral) 7481 { 7482 apr_array_header_t *child_with_mergeinfo; 7483 svn_client__merge_path_t *target_info; 7484 7485 /* If we have ancestrally related sources and more than one 7486 range to merge, eliminate no-op ranges before going through 7487 the effort of downloading the many copies of the file 7488 required to do these merges (two copies per range). */ 7489 if (remaining_ranges->nelts > 1) 7490 { 7491 const char *old_sess_url; 7492 svn_error_t *err; 7493 7494 SVN_ERR(svn_client__ensure_ra_session_url(&old_sess_url, 7495 merge_b->ra_session1, 7496 primary_src->url, 7497 iterpool)); 7498 err = remove_noop_merge_ranges(&ranges_to_merge, 7499 merge_b->ra_session1, 7500 remaining_ranges, scratch_pool); 7501 SVN_ERR(svn_error_compose_create( 7502 err, svn_ra_reparent(merge_b->ra_session1, 7503 old_sess_url, iterpool))); 7504 } 7505 7506 /* To support notify_merge_begin() initialize our 7507 CHILD_WITH_MERGEINFO. See the comment 7508 'THE CHILDREN_WITH_MERGEINFO ARRAY' at the start of this file. */ 7509 7510 child_with_mergeinfo = apr_array_make(scratch_pool, 1, 7511 sizeof(svn_client__merge_path_t *)); 7512 7513 /* ### Create a fake copy of merge_target as we don't keep 7514 remaining_ranges in sync (yet). */ 7515 target_info = apr_pcalloc(scratch_pool, sizeof(*target_info)); 7516 7517 target_info->abspath = merge_target->abspath; 7518 target_info->remaining_ranges = ranges_to_merge; 7519 7520 APR_ARRAY_PUSH(child_with_mergeinfo, svn_client__merge_path_t *) 7521 = target_info; 7522 7523 /* And store in baton to allow using it from notify_merge_begin() */ 7524 merge_b->notify_begin.nodes_with_mergeinfo = child_with_mergeinfo; 7525 } 7526 7527 while (ranges_to_merge->nelts > 0) 7528 { 7529 svn_merge_range_t *r = APR_ARRAY_IDX(ranges_to_merge, 0, 7530 svn_merge_range_t *); 7531 const merge_source_t *real_source; 7532 const char *left_file, *right_file; 7533 apr_hash_t *left_props, *right_props; 7534 const svn_diff_source_t *left_source; 7535 const svn_diff_source_t *right_source; 7536 7537 svn_pool_clear(iterpool); 7538 7539 /* Ensure any subsequent drives gets their own notification. */ 7540 merge_b->notify_begin.last_abspath = NULL; 7541 7542 /* While we currently don't allow it, in theory we could be 7543 fetching two fulltexts from two different repositories here. */ 7544 if (source->ancestral) 7545 real_source = subrange_source(source, r->start, r->end, iterpool); 7546 else 7547 real_source = source; 7548 SVN_ERR(single_file_merge_get_file(&left_file, &left_props, 7549 merge_b->ra_session1, 7550 real_source->loc1, 7551 target_abspath, 7552 iterpool, iterpool)); 7553 SVN_ERR(single_file_merge_get_file(&right_file, &right_props, 7554 merge_b->ra_session2, 7555 real_source->loc2, 7556 target_abspath, 7557 iterpool, iterpool)); 7558 /* Calculate sources for the diff processor */ 7559 left_source = svn_diff__source_create(r->start, iterpool); 7560 right_source = svn_diff__source_create(r->end, iterpool); 7561 7562 7563 /* If the sources are related or we're ignoring ancestry in diffs, 7564 do a text-n-props merge; otherwise, do a delete-n-add merge. */ 7565 if (! (merge_b->diff_ignore_ancestry || sources_related)) 7566 { 7567 struct merge_dir_baton_t dir_baton; 7568 void *file_baton; 7569 svn_boolean_t skip; 7570 7571 /* Initialize minimal dir baton to allow calculating 'R'eplace 7572 from 'D'elete + 'A'dd. */ 7573 7574 memset(&dir_baton, 0, sizeof(dir_baton)); 7575 dir_baton.pool = iterpool; 7576 dir_baton.tree_conflict_reason = CONFLICT_REASON_NONE; 7577 dir_baton.tree_conflict_action = svn_wc_conflict_action_edit; 7578 dir_baton.skip_reason = svn_wc_notify_state_unknown; 7579 7580 /* Delete... */ 7581 file_baton = NULL; 7582 skip = FALSE; 7583 SVN_ERR(processor->file_opened(&file_baton, &skip, target_relpath, 7584 left_source, 7585 NULL /* right_source */, 7586 NULL /* copyfrom_source */, 7587 &dir_baton, 7588 processor, 7589 iterpool, iterpool)); 7590 if (! skip) 7591 SVN_ERR(processor->file_deleted(target_relpath, 7592 left_source, 7593 left_file, 7594 left_props, 7595 file_baton, 7596 processor, 7597 iterpool)); 7598 7599 /* ...plus add... */ 7600 file_baton = NULL; 7601 skip = FALSE; 7602 SVN_ERR(processor->file_opened(&file_baton, &skip, target_relpath, 7603 NULL /* left_source */, 7604 right_source, 7605 NULL /* copyfrom_source */, 7606 &dir_baton, 7607 processor, 7608 iterpool, iterpool)); 7609 if (! skip) 7610 SVN_ERR(processor->file_added(target_relpath, 7611 NULL /* copyfrom_source */, 7612 right_source, 7613 NULL /* copyfrom_file */, 7614 right_file, 7615 NULL /* copyfrom_props */, 7616 right_props, 7617 file_baton, 7618 processor, 7619 iterpool)); 7620 /* ... equals replace. */ 7621 } 7622 else 7623 { 7624 void *file_baton = NULL; 7625 svn_boolean_t skip = FALSE; 7626 apr_array_header_t *propchanges; 7627 7628 7629 /* Deduce property diffs. */ 7630 SVN_ERR(svn_prop_diffs(&propchanges, right_props, left_props, 7631 iterpool)); 7632 7633 SVN_ERR(processor->file_opened(&file_baton, &skip, target_relpath, 7634 left_source, 7635 right_source, 7636 NULL /* copyfrom_source */, 7637 NULL /* dir_baton */, 7638 processor, 7639 iterpool, iterpool)); 7640 if (! skip) 7641 SVN_ERR(processor->file_changed(target_relpath, 7642 left_source, 7643 right_source, 7644 left_file, 7645 right_file, 7646 left_props, 7647 right_props, 7648 TRUE /* file changed */, 7649 propchanges, 7650 file_baton, 7651 processor, 7652 iterpool)); 7653 } 7654 7655 if (is_path_conflicted_by_merge(merge_b)) 7656 { 7657 merge_source_t *remaining_range = NULL; 7658 7659 if (real_source->loc2->rev != source->loc2->rev) 7660 remaining_range = subrange_source(source, 7661 real_source->loc2->rev, 7662 source->loc2->rev, 7663 scratch_pool); 7664 *conflict_report = single_range_conflict_report_create( 7665 real_source, remaining_range, result_pool); 7666 7667 /* Only record partial mergeinfo if only a partial merge was 7668 performed before a conflict was encountered. */ 7669 range.end = r->end; 7670 break; 7671 } 7672 7673 /* Now delete the just merged range from the hash 7674 (This list is used from notify_merge_begin) 7675 7676 Directory merges use remove_first_range_from_remaining_ranges() */ 7677 svn_sort__array_delete(ranges_to_merge, 0, 1); 7678 } 7679 merge_b->notify_begin.last_abspath = NULL; 7680 } /* !merge_b->record_only */ 7681 7682 /* Record updated WC mergeinfo to account for our new merges, minus 7683 any unresolved conflicts and skips. We use the original 7684 REMAINING_RANGES here because we want to record all the requested 7685 merge ranges, include the noop ones. */ 7686 if (RECORD_MERGEINFO(merge_b) && remaining_ranges->nelts) 7687 { 7688 const char *mergeinfo_path = svn_client__pathrev_fspath(primary_src, 7689 scratch_pool); 7690 svn_rangelist_t *filtered_rangelist; 7691 7692 /* Filter any ranges from TARGET_WCPATH's own history, there is no 7693 need to record this explicitly in mergeinfo, it is already part 7694 of TARGET_WCPATH's natural history (implicit mergeinfo). */ 7695 SVN_ERR(filter_natural_history_from_mergeinfo( 7696 &filtered_rangelist, 7697 mergeinfo_path, 7698 merge_target->implicit_mergeinfo, 7699 &range, 7700 iterpool)); 7701 7702 /* Only record mergeinfo if there is something other than 7703 self-referential mergeinfo, but don't record mergeinfo if 7704 TARGET_WCPATH was skipped. */ 7705 if (filtered_rangelist->nelts 7706 && (apr_hash_count(merge_b->skipped_abspaths) == 0)) 7707 { 7708 apr_hash_t *merges = apr_hash_make(iterpool); 7709 7710 /* If merge target has inherited mergeinfo set it before 7711 recording the first merge range. */ 7712 if (inherited) 7713 SVN_ERR(svn_client__record_wc_mergeinfo(target_abspath, 7714 target_mergeinfo, 7715 FALSE, ctx, 7716 iterpool)); 7717 7718 svn_hash_sets(merges, target_abspath, filtered_rangelist); 7719 7720 if (!squelch_mergeinfo_notifications) 7721 { 7722 /* Notify that we are recording mergeinfo describing a merge. */ 7723 svn_merge_range_t n_range; 7724 7725 SVN_ERR(svn_mergeinfo__get_range_endpoints( 7726 &n_range.end, &n_range.start, merges, iterpool)); 7727 n_range.inheritable = TRUE; 7728 notify_mergeinfo_recording(target_abspath, &n_range, 7729 merge_b->ctx, iterpool); 7730 } 7731 7732 SVN_ERR(update_wc_mergeinfo(result_catalog, target_abspath, 7733 mergeinfo_path, merges, is_rollback, 7734 ctx, iterpool)); 7735 } 7736 } 7737 7738 merge_b->notify_begin.nodes_with_mergeinfo = NULL; 7739 7740 svn_pool_destroy(iterpool); 7741 7742 return SVN_NO_ERROR; 7743} 7744 7745/* Helper for do_directory_merge() to handle the case where a merge editor 7746 drive adds explicit mergeinfo to a path which didn't have any explicit 7747 mergeinfo previously. 7748 7749 MERGE_B is cascaded from the argument of the same 7750 name in do_directory_merge(). Should be called only after 7751 do_directory_merge() has called populate_remaining_ranges() and populated 7752 the remaining_ranges field of each child in 7753 CHILDREN_WITH_MERGEINFO (i.e. the remaining_ranges fields can be 7754 empty but never NULL). 7755 7756 If MERGE_B->DRY_RUN is true do nothing, if it is false then 7757 for each path (if any) in MERGE_B->PATHS_WITH_NEW_MERGEINFO merge that 7758 path's inherited mergeinfo (if any) with its working explicit mergeinfo 7759 and set that as the path's new explicit mergeinfo. Then add an 7760 svn_client__merge_path_t * element representing the path to 7761 CHILDREN_WITH_MERGEINFO if it isn't already present. All fields 7762 in any elements added to CHILDREN_WITH_MERGEINFO are initialized 7763 to FALSE/NULL with the exception of 'path' and 'remaining_ranges'. The 7764 latter is set to a rangelist equal to the remaining_ranges of the path's 7765 nearest path-wise ancestor in CHILDREN_WITH_MERGEINFO. 7766 7767 Any elements added to CHILDREN_WITH_MERGEINFO are allocated 7768 in POOL. */ 7769static svn_error_t * 7770process_children_with_new_mergeinfo(merge_cmd_baton_t *merge_b, 7771 apr_array_header_t *children_with_mergeinfo, 7772 apr_pool_t *pool) 7773{ 7774 apr_pool_t *iterpool; 7775 apr_hash_index_t *hi; 7776 7777 if (!merge_b->paths_with_new_mergeinfo || merge_b->dry_run) 7778 return SVN_NO_ERROR; 7779 7780 /* Iterate over each path with explicit mergeinfo added by the merge. */ 7781 iterpool = svn_pool_create(pool); 7782 for (hi = apr_hash_first(pool, merge_b->paths_with_new_mergeinfo); 7783 hi; 7784 hi = apr_hash_next(hi)) 7785 { 7786 const char *abspath_with_new_mergeinfo = svn__apr_hash_index_key(hi); 7787 svn_mergeinfo_t path_inherited_mergeinfo; 7788 svn_mergeinfo_t path_explicit_mergeinfo; 7789 svn_client__merge_path_t *new_child; 7790 7791 svn_pool_clear(iterpool); 7792 7793 /* Note: We could skip recording inherited mergeinfo here if this path 7794 was added (with preexisting mergeinfo) by the merge. That's actually 7795 more correct, since the inherited mergeinfo likely describes 7796 non-existent or unrelated merge history, but it's not quite so simple 7797 as that, see http://subversion.tigris.org/issues/show_bug.cgi?id=4309 7798 */ 7799 7800 /* Get the path's new explicit mergeinfo... */ 7801 SVN_ERR(svn_client__get_wc_mergeinfo(&path_explicit_mergeinfo, NULL, 7802 svn_mergeinfo_explicit, 7803 abspath_with_new_mergeinfo, 7804 NULL, NULL, FALSE, 7805 merge_b->ctx, 7806 iterpool, iterpool)); 7807 /* ...there *should* always be explicit mergeinfo at this point 7808 but you can't be too careful. */ 7809 if (path_explicit_mergeinfo) 7810 { 7811 /* Get the mergeinfo the path would have inherited before 7812 the merge. */ 7813 SVN_ERR(svn_client__get_wc_or_repos_mergeinfo( 7814 &path_inherited_mergeinfo, 7815 NULL, NULL, 7816 FALSE, 7817 svn_mergeinfo_nearest_ancestor, /* We only want inherited MI */ 7818 merge_b->ra_session2, 7819 abspath_with_new_mergeinfo, 7820 merge_b->ctx, 7821 iterpool)); 7822 7823 /* If the path inherited any mergeinfo then merge that with the 7824 explicit mergeinfo and record the result as the path's new 7825 explicit mergeinfo. */ 7826 if (path_inherited_mergeinfo) 7827 { 7828 SVN_ERR(svn_mergeinfo_merge2(path_explicit_mergeinfo, 7829 path_inherited_mergeinfo, 7830 iterpool, iterpool)); 7831 SVN_ERR(svn_client__record_wc_mergeinfo( 7832 abspath_with_new_mergeinfo, 7833 path_explicit_mergeinfo, 7834 FALSE, merge_b->ctx, iterpool)); 7835 } 7836 7837 /* If the path is not in CHILDREN_WITH_MERGEINFO then add it. */ 7838 new_child = 7839 get_child_with_mergeinfo(children_with_mergeinfo, 7840 abspath_with_new_mergeinfo); 7841 if (!new_child) 7842 { 7843 const svn_client__merge_path_t *parent 7844 = find_nearest_ancestor(children_with_mergeinfo, 7845 FALSE, abspath_with_new_mergeinfo); 7846 new_child 7847 = svn_client__merge_path_create(abspath_with_new_mergeinfo, 7848 pool); 7849 7850 /* If path_with_new_mergeinfo is the merge target itself 7851 then it should already be in 7852 CHILDREN_WITH_MERGEINFO per the criteria of 7853 get_mergeinfo_paths() and we shouldn't be in this block. 7854 If path_with_new_mergeinfo is a subtree then it must have 7855 a parent in CHILDREN_WITH_MERGEINFO if only 7856 the merge target itself...so if we don't find a parent 7857 the caller has done something quite wrong. */ 7858 SVN_ERR_ASSERT(parent); 7859 SVN_ERR_ASSERT(parent->remaining_ranges); 7860 7861 /* Set the path's remaining_ranges equal to its parent's. */ 7862 new_child->remaining_ranges = svn_rangelist_dup( 7863 parent->remaining_ranges, pool); 7864 insert_child_to_merge(children_with_mergeinfo, new_child, pool); 7865 } 7866 } 7867 } 7868 svn_pool_destroy(iterpool); 7869 7870 return SVN_NO_ERROR; 7871} 7872 7873/* Return true if any path in SUBTREES is equal to, or is a subtree of, 7874 LOCAL_ABSPATH. Return false otherwise. The keys of SUBTREES are 7875 (const char *) absolute paths and its values are irrelevant. 7876 If SUBTREES is NULL return false. */ 7877static svn_boolean_t 7878path_is_subtree(const char *local_abspath, 7879 apr_hash_t *subtrees, 7880 apr_pool_t *pool) 7881{ 7882 if (subtrees) 7883 { 7884 apr_hash_index_t *hi; 7885 7886 for (hi = apr_hash_first(pool, subtrees); 7887 hi; hi = apr_hash_next(hi)) 7888 { 7889 const char *path_touched_by_merge = svn__apr_hash_index_key(hi); 7890 if (svn_dirent_is_ancestor(local_abspath, path_touched_by_merge)) 7891 return TRUE; 7892 } 7893 } 7894 return FALSE; 7895} 7896 7897/* Return true if any merged, skipped, added or tree-conflicted path 7898 recorded in MERGE_B is equal to, or is a subtree of LOCAL_ABSPATH. Return 7899 false otherwise. 7900 7901 ### Why not text- or prop-conflicted paths? Are such paths guaranteed 7902 to be recorded as 'merged' or 'skipped' or 'added', perhaps? 7903*/ 7904static svn_boolean_t 7905subtree_touched_by_merge(const char *local_abspath, 7906 merge_cmd_baton_t *merge_b, 7907 apr_pool_t *pool) 7908{ 7909 return (path_is_subtree(local_abspath, merge_b->merged_abspaths, pool) 7910 || path_is_subtree(local_abspath, merge_b->skipped_abspaths, pool) 7911 || path_is_subtree(local_abspath, merge_b->added_abspaths, pool) 7912 || path_is_subtree(local_abspath, merge_b->tree_conflicted_abspaths, 7913 pool)); 7914} 7915 7916/* Helper for do_directory_merge() when performing mergeinfo unaware merges. 7917 7918 Merge the SOURCE diff into TARGET_DIR_WCPATH. 7919 7920 SOURCE, DEPTH, NOTIFY_B, and MERGE_B 7921 are all cascaded from do_directory_merge's arguments of the same names. 7922 7923 CONFLICT_REPORT is as documented for do_directory_merge(). 7924 7925 NOTE: This is a very thin wrapper around drive_merge_report_editor() and 7926 exists only to populate CHILDREN_WITH_MERGEINFO with the single element 7927 expected during mergeinfo unaware merges. 7928*/ 7929static svn_error_t * 7930do_mergeinfo_unaware_dir_merge(single_range_conflict_report_t **conflict_report, 7931 const merge_source_t *source, 7932 const char *target_dir_wcpath, 7933 apr_array_header_t *children_with_mergeinfo, 7934 const svn_diff_tree_processor_t *processor, 7935 svn_depth_t depth, 7936 merge_cmd_baton_t *merge_b, 7937 apr_pool_t *result_pool, 7938 apr_pool_t *scratch_pool) 7939{ 7940 /* Initialize CHILDREN_WITH_MERGEINFO and populate it with 7941 one element describing the merge of SOURCE->rev1:rev2 to 7942 TARGET_DIR_WCPATH. */ 7943 svn_client__merge_path_t *item 7944 = svn_client__merge_path_create(target_dir_wcpath, scratch_pool); 7945 7946 *conflict_report = NULL; 7947 item->remaining_ranges = svn_rangelist__initialize(source->loc1->rev, 7948 source->loc2->rev, 7949 TRUE, scratch_pool); 7950 APR_ARRAY_PUSH(children_with_mergeinfo, 7951 svn_client__merge_path_t *) = item; 7952 SVN_ERR(drive_merge_report_editor(target_dir_wcpath, 7953 source, 7954 NULL, processor, depth, 7955 merge_b, scratch_pool)); 7956 if (is_path_conflicted_by_merge(merge_b)) 7957 { 7958 *conflict_report = single_range_conflict_report_create( 7959 source, NULL, result_pool); 7960 } 7961 return SVN_NO_ERROR; 7962} 7963 7964/* A svn_log_entry_receiver_t baton for log_find_operative_subtree_revs(). */ 7965typedef struct log_find_operative_subtree_baton_t 7966{ 7967 /* Mapping of const char * absolute working copy paths to those 7968 path's const char * repos absolute paths. */ 7969 apr_hash_t *operative_children; 7970 7971 /* As per the arguments of the same name to 7972 get_operative_immediate_children(). */ 7973 const char *merge_source_fspath; 7974 const char *merge_target_abspath; 7975 svn_depth_t depth; 7976 svn_wc_context_t *wc_ctx; 7977 7978 /* A pool to allocate additions to the hashes in. */ 7979 apr_pool_t *result_pool; 7980} log_find_operative_subtree_baton_t; 7981 7982/* A svn_log_entry_receiver_t callback for 7983 get_inoperative_immediate_children(). */ 7984static svn_error_t * 7985log_find_operative_subtree_revs(void *baton, 7986 svn_log_entry_t *log_entry, 7987 apr_pool_t *pool) 7988{ 7989 log_find_operative_subtree_baton_t *log_baton = baton; 7990 apr_hash_index_t *hi; 7991 apr_pool_t *iterpool; 7992 7993 /* It's possible that authz restrictions on the merge source prevent us 7994 from knowing about any of the changes for LOG_ENTRY->REVISION. */ 7995 if (!log_entry->changed_paths2) 7996 return SVN_NO_ERROR; 7997 7998 iterpool = svn_pool_create(pool); 7999 8000 for (hi = apr_hash_first(pool, log_entry->changed_paths2); 8001 hi; 8002 hi = apr_hash_next(hi)) 8003 { 8004 const char *path = svn__apr_hash_index_key(hi); 8005 svn_log_changed_path2_t *change = svn__apr_hash_index_val(hi); 8006 8007 { 8008 const char *child; 8009 const char *potential_child; 8010 const char *rel_path = 8011 svn_fspath__skip_ancestor(log_baton->merge_source_fspath, path); 8012 8013 /* Some affected paths might be the root of the merge source or 8014 entirely outside our subtree of interest. In either case they 8015 are not operative *immediate* children. */ 8016 if (rel_path == NULL 8017 || rel_path[0] == '\0') 8018 continue; 8019 8020 svn_pool_clear(iterpool); 8021 8022 child = svn_relpath_dirname(rel_path, iterpool); 8023 if (child[0] == '\0') 8024 { 8025 /* The svn_log_changed_path2_t.node_kind members in 8026 LOG_ENTRY->CHANGED_PATHS2 may be set to 8027 svn_node_unknown, see svn_log_changed_path2_t and 8028 svn_fs_paths_changed2. In that case we check the 8029 type of the corresponding subtree in the merge 8030 target. */ 8031 svn_node_kind_t node_kind; 8032 8033 if (change->node_kind == svn_node_unknown) 8034 { 8035 const char *wc_child_abspath = 8036 svn_dirent_join(log_baton->merge_target_abspath, 8037 rel_path, iterpool); 8038 8039 SVN_ERR(svn_wc_read_kind2(&node_kind, log_baton->wc_ctx, 8040 wc_child_abspath, FALSE, FALSE, 8041 iterpool)); 8042 } 8043 else 8044 { 8045 node_kind = change->node_kind; 8046 } 8047 8048 /* We only care about immediate directory children if 8049 DEPTH is svn_depth_files. */ 8050 if (log_baton->depth == svn_depth_files 8051 && node_kind != svn_node_dir) 8052 continue; 8053 8054 /* If depth is svn_depth_immediates, then we only care 8055 about changes to proper subtrees of PATH. If the change 8056 is to PATH itself then PATH is within the operational 8057 depth of the merge. */ 8058 if (log_baton->depth == svn_depth_immediates) 8059 continue; 8060 8061 child = rel_path; 8062 } 8063 8064 potential_child = svn_dirent_join(log_baton->merge_target_abspath, 8065 child, iterpool); 8066 8067 if (change->action == 'A' 8068 || !svn_hash_gets(log_baton->operative_children, 8069 potential_child)) 8070 { 8071 svn_hash_sets(log_baton->operative_children, 8072 apr_pstrdup(log_baton->result_pool, 8073 potential_child), 8074 apr_pstrdup(log_baton->result_pool, path)); 8075 } 8076 } 8077 } 8078 svn_pool_destroy(iterpool); 8079 return SVN_NO_ERROR; 8080} 8081 8082/* Find immediate subtrees of MERGE_TARGET_ABSPATH which would have 8083 additional differences applied if record_mergeinfo_for_dir_merge() were 8084 recording mergeinfo describing a merge at svn_depth_infinity, rather 8085 than at DEPTH (which is assumed to be shallow; if 8086 DEPTH == svn_depth_infinity then this function does nothing beyond 8087 setting *OPERATIVE_CHILDREN to an empty hash). 8088 8089 MERGE_SOURCE_FSPATH is the absolute repository path of the merge 8090 source. OLDEST_REV and YOUNGEST_REV are the revisions merged from 8091 MERGE_SOURCE_FSPATH to MERGE_TARGET_ABSPATH. 8092 8093 RA_SESSION points to MERGE_SOURCE_FSPATH. 8094 8095 Set *OPERATIVE_CHILDREN to a hash (mapping const char * absolute 8096 working copy paths to those path's const char * repos absolute paths) 8097 containing all the immediate subtrees of MERGE_TARGET_ABSPATH which would 8098 have a different diff applied if MERGE_SOURCE_FSPATH 8099 -r(OLDEST_REV - 1):YOUNGEST_REV were merged to MERGE_TARGET_ABSPATH at 8100 svn_depth_infinity rather than DEPTH. 8101 8102 RESULT_POOL is used to allocate the contents of *OPERATIVE_CHILDREN. 8103 SCRATCH_POOL is used for temporary allocations. */ 8104static svn_error_t * 8105get_operative_immediate_children(apr_hash_t **operative_children, 8106 const char *merge_source_fspath, 8107 svn_revnum_t oldest_rev, 8108 svn_revnum_t youngest_rev, 8109 const char *merge_target_abspath, 8110 svn_depth_t depth, 8111 svn_wc_context_t *wc_ctx, 8112 svn_ra_session_t *ra_session, 8113 apr_pool_t *result_pool, 8114 apr_pool_t *scratch_pool) 8115{ 8116 log_find_operative_subtree_baton_t log_baton; 8117 8118 SVN_ERR_ASSERT(SVN_IS_VALID_REVNUM(oldest_rev)); 8119 SVN_ERR_ASSERT(SVN_IS_VALID_REVNUM(youngest_rev)); 8120 SVN_ERR_ASSERT(oldest_rev <= youngest_rev); 8121 8122 *operative_children = apr_hash_make(result_pool); 8123 8124 if (depth == svn_depth_infinity) 8125 return SVN_NO_ERROR; 8126 8127 /* Now remove any paths from *OPERATIVE_CHILDREN that are inoperative when 8128 merging MERGE_SOURCE_REPOS_PATH -r(OLDEST_REV - 1):YOUNGEST_REV to 8129 MERGE_TARGET_ABSPATH at --depth infinity. */ 8130 log_baton.operative_children = *operative_children; 8131 log_baton.merge_source_fspath = merge_source_fspath; 8132 log_baton.merge_target_abspath = merge_target_abspath; 8133 log_baton.depth = depth; 8134 log_baton.wc_ctx = wc_ctx; 8135 log_baton.result_pool = result_pool; 8136 8137 SVN_ERR(get_log(ra_session, "", youngest_rev, oldest_rev, 8138 TRUE, /* discover_changed_paths */ 8139 log_find_operative_subtree_revs, 8140 &log_baton, scratch_pool)); 8141 8142 return SVN_NO_ERROR; 8143} 8144 8145/* Helper for record_mergeinfo_for_dir_merge(): Identify which elements of 8146 CHILDREN_WITH_MERGEINFO need new mergeinfo set to accurately 8147 describe a merge, what inheritance type such new mergeinfo should have, 8148 and what subtrees can be ignored altogether. 8149 8150 For each svn_client__merge_path_t CHILD in CHILDREN_WITH_MERGEINFO, 8151 set CHILD->RECORD_MERGEINFO and CHILD->RECORD_NONINHERITABLE to true 8152 if the subtree needs mergeinfo to describe the merge and if that 8153 mergeinfo should be non-inheritable respectively. 8154 8155 If OPERATIVE_MERGE is true, then the merge being described is operative 8156 as per subtree_touched_by_merge(). OPERATIVE_MERGE is false otherwise. 8157 8158 MERGED_RANGE, MERGEINFO_FSPATH, DEPTH, NOTIFY_B, and MERGE_B are all 8159 cascaded from record_mergeinfo_for_dir_merge's arguments of the same 8160 names. 8161 8162 SCRATCH_POOL is used for temporary allocations. 8163*/ 8164static svn_error_t * 8165flag_subtrees_needing_mergeinfo(svn_boolean_t operative_merge, 8166 const svn_merge_range_t *merged_range, 8167 apr_array_header_t *children_with_mergeinfo, 8168 const char *mergeinfo_fspath, 8169 svn_depth_t depth, 8170 merge_cmd_baton_t *merge_b, 8171 apr_pool_t *scratch_pool) 8172{ 8173 apr_pool_t *iterpool = svn_pool_create(scratch_pool); 8174 int i; 8175 apr_hash_t *operative_immediate_children = NULL; 8176 8177 assert(! merge_b->dry_run); 8178 8179 if (!merge_b->record_only 8180 && merged_range->start <= merged_range->end 8181 && (depth < svn_depth_infinity)) 8182 SVN_ERR(get_operative_immediate_children( 8183 &operative_immediate_children, 8184 mergeinfo_fspath, merged_range->start + 1, merged_range->end, 8185 merge_b->target->abspath, depth, merge_b->ctx->wc_ctx, 8186 merge_b->ra_session1, scratch_pool, iterpool)); 8187 8188 /* Issue #4056: Walk NOTIFY_B->CHILDREN_WITH_MERGEINFO reverse depth-first 8189 order. This way each child knows if it has operative missing/switched 8190 children which necessitates non-inheritable mergeinfo. */ 8191 for (i = children_with_mergeinfo->nelts - 1; i >= 0; i--) 8192 { 8193 svn_client__merge_path_t *child = 8194 APR_ARRAY_IDX(children_with_mergeinfo, i, 8195 svn_client__merge_path_t *); 8196 8197 /* Can't record mergeinfo on something that isn't here. */ 8198 if (child->absent) 8199 continue; 8200 8201 /* Verify that remove_children_with_deleted_mergeinfo() did its job */ 8202 assert((i == 0) 8203 ||! merge_b->paths_with_deleted_mergeinfo 8204 || !svn_hash_gets(merge_b->paths_with_deleted_mergeinfo, 8205 child->abspath)); 8206 8207 /* Don't record mergeinfo on skipped paths. */ 8208 if (svn_hash_gets(merge_b->skipped_abspaths, child->abspath)) 8209 continue; 8210 8211 /* ### ptb: Yes, we could combine the following into a single 8212 ### conditional, but clarity would suffer (even more than 8213 ### it does now). */ 8214 if (i == 0) 8215 { 8216 /* Always record mergeinfo on the merge target. */ 8217 child->record_mergeinfo = TRUE; 8218 } 8219 else if (merge_b->record_only && !merge_b->reintegrate_merge) 8220 { 8221 /* Always record mergeinfo for --record-only merges. */ 8222 child->record_mergeinfo = TRUE; 8223 } 8224 else if (child->immediate_child_dir 8225 && !child->pre_merge_mergeinfo 8226 && operative_immediate_children 8227 && svn_hash_gets(operative_immediate_children, child->abspath)) 8228 { 8229 /* We must record mergeinfo on those issue #3642 children 8230 that are operative at a greater depth. */ 8231 child->record_mergeinfo = TRUE; 8232 } 8233 8234 if (operative_merge 8235 && subtree_touched_by_merge(child->abspath, merge_b, iterpool)) 8236 { 8237 svn_pool_clear(iterpool); 8238 8239 /* This subtree was affected by the merge. */ 8240 child->record_mergeinfo = TRUE; 8241 8242 /* Were any CHILD's missing children skipped by the merge? 8243 If not, then CHILD's missing children don't need to be 8244 considered when recording mergeinfo describing the merge. */ 8245 if (! merge_b->reintegrate_merge 8246 && child->missing_child 8247 && !path_is_subtree(child->abspath, 8248 merge_b->skipped_abspaths, 8249 iterpool)) 8250 { 8251 child->missing_child = FALSE; 8252 } 8253 8254 /* If CHILD has an immediate switched child or children and 8255 none of these were touched by the merge, then we don't need 8256 need to do any special handling of those switched subtrees 8257 (e.g. record non-inheritable mergeinfo) when recording 8258 mergeinfo describing the merge. */ 8259 if (child->switched_child) 8260 { 8261 int j; 8262 svn_boolean_t operative_switched_child = FALSE; 8263 8264 for (j = i + 1; 8265 j < children_with_mergeinfo->nelts; 8266 j++) 8267 { 8268 svn_client__merge_path_t *potential_child = 8269 APR_ARRAY_IDX(children_with_mergeinfo, j, 8270 svn_client__merge_path_t *); 8271 if (!svn_dirent_is_ancestor(child->abspath, 8272 potential_child->abspath)) 8273 break; 8274 8275 /* POTENTIAL_CHILD is a subtree of CHILD, but is it 8276 an immediate child? */ 8277 if (strcmp(child->abspath, 8278 svn_dirent_dirname(potential_child->abspath, 8279 iterpool))) 8280 continue; 8281 8282 if (potential_child->switched 8283 && potential_child->record_mergeinfo) 8284 { 8285 operative_switched_child = TRUE; 8286 break; 8287 } 8288 } 8289 8290 /* Can we treat CHILD as if it has no switched children? */ 8291 if (! operative_switched_child) 8292 child->switched_child = FALSE; 8293 } 8294 } 8295 8296 if (child->record_mergeinfo) 8297 { 8298 /* We need to record mergeinfo, but should that mergeinfo be 8299 non-inheritable? */ 8300 svn_node_kind_t path_kind; 8301 SVN_ERR(svn_wc_read_kind2(&path_kind, merge_b->ctx->wc_ctx, 8302 child->abspath, FALSE, FALSE, iterpool)); 8303 8304 /* Only directories can have non-inheritable mergeinfo. */ 8305 if (path_kind == svn_node_dir) 8306 { 8307 /* There are two general cases where non-inheritable mergeinfo 8308 is required: 8309 8310 1) There merge target has missing subtrees (due to authz 8311 restrictions, switched subtrees, or a shallow working 8312 copy). 8313 8314 2) The operational depth of the merge itself is shallow. */ 8315 8316 /* We've already determined the first case. */ 8317 child->record_noninheritable = 8318 child->missing_child || child->switched_child; 8319 8320 /* The second case requires a bit more work. */ 8321 if (i == 0) 8322 { 8323 /* If CHILD is the root of the merge target and the 8324 operational depth is empty or files, then the mere 8325 existence of operative immediate children means we 8326 must record non-inheritable mergeinfo. 8327 8328 ### What about svn_depth_immediates? In that case 8329 ### the merge target needs only normal inheritable 8330 ### mergeinfo and the target's immediate children will 8331 ### get non-inheritable mergeinfo, assuming they 8332 ### need even that. */ 8333 if (depth < svn_depth_immediates 8334 && operative_immediate_children 8335 && apr_hash_count(operative_immediate_children)) 8336 child->record_noninheritable = TRUE; 8337 } 8338 else if (depth == svn_depth_immediates) 8339 { 8340 /* An immediate directory child of the merge target, which 8341 was affected by a --depth=immediates merge, needs 8342 non-inheritable mergeinfo. */ 8343 if (svn_hash_gets(operative_immediate_children, 8344 child->abspath)) 8345 child->record_noninheritable = TRUE; 8346 } 8347 } 8348 } 8349 else /* child->record_mergeinfo */ 8350 { 8351 /* If CHILD is in NOTIFY_B->CHILDREN_WITH_MERGEINFO simply 8352 because it had no explicit mergeinfo of its own at the 8353 start of the merge but is the child of of some path with 8354 non-inheritable mergeinfo, then the explicit mergeinfo it 8355 has *now* was set by get_mergeinfo_paths() -- see criteria 8356 3 in that function's doc string. So since CHILD->ABSPATH 8357 was not touched by the merge we can remove the 8358 mergeinfo. */ 8359 if (child->child_of_noninheritable) 8360 SVN_ERR(svn_client__record_wc_mergeinfo(child->abspath, 8361 NULL, FALSE, 8362 merge_b->ctx, 8363 iterpool)); 8364 } 8365 } 8366 8367 svn_pool_destroy(iterpool); 8368 return SVN_NO_ERROR; 8369} 8370 8371/* Helper for do_directory_merge(). 8372 8373 If RESULT_CATALOG is NULL then record mergeinfo describing a merge of 8374 MERGED_RANGE->START:MERGED_RANGE->END from the repository relative path 8375 MERGEINFO_FSPATH to the merge target (and possibly its subtrees) described 8376 by NOTIFY_B->CHILDREN_WITH_MERGEINFO -- see the global comment 8377 'THE CHILDREN_WITH_MERGEINFO ARRAY'. Obviously this should only 8378 be called if recording mergeinfo -- see doc string for RECORD_MERGEINFO(). 8379 8380 If RESULT_CATALOG is not NULL, then don't record the new mergeinfo on the 8381 WC, but instead record it in RESULT_CATALOG, where the keys are absolute 8382 working copy paths and the values are the new mergeinfos for each. 8383 Allocate additions to RESULT_CATALOG in pool which RESULT_CATALOG was 8384 created in. 8385 8386 DEPTH, NOTIFY_B, MERGE_B, and SQUELCH_MERGEINFO_NOTIFICATIONS are all 8387 cascaded from do_directory_merge's arguments of the same names. 8388 8389 SCRATCH_POOL is used for temporary allocations. 8390*/ 8391static svn_error_t * 8392record_mergeinfo_for_dir_merge(svn_mergeinfo_catalog_t result_catalog, 8393 const svn_merge_range_t *merged_range, 8394 const char *mergeinfo_fspath, 8395 apr_array_header_t *children_with_mergeinfo, 8396 svn_depth_t depth, 8397 svn_boolean_t squelch_mergeinfo_notifications, 8398 merge_cmd_baton_t *merge_b, 8399 apr_pool_t *scratch_pool) 8400{ 8401 int i; 8402 svn_boolean_t is_rollback = (merged_range->start > merged_range->end); 8403 svn_boolean_t operative_merge; 8404 8405 /* Update the WC mergeinfo here to account for our new 8406 merges, minus any unresolved conflicts and skips. */ 8407 8408 /* We need a scratch pool for iterations below. */ 8409 apr_pool_t *iterpool = svn_pool_create(scratch_pool); 8410 8411 svn_merge_range_t range = *merged_range; 8412 8413 assert(! merge_b->dry_run); 8414 8415 /* Regardless of what subtrees in MERGE_B->target->abspath might be missing 8416 could this merge have been operative? */ 8417 operative_merge = subtree_touched_by_merge(merge_b->target->abspath, 8418 merge_b, iterpool); 8419 8420 /* If this couldn't be an operative merge then don't bother with 8421 the added complexity (and user confusion) of non-inheritable ranges. 8422 There is no harm in subtrees inheriting inoperative mergeinfo. */ 8423 if (!operative_merge) 8424 range.inheritable = TRUE; 8425 8426 /* Remove absent children at or under MERGE_B->target->abspath from 8427 NOTIFY_B->CHILDREN_WITH_MERGEINFO 8428 before we calculate the merges performed. */ 8429 remove_absent_children(merge_b->target->abspath, 8430 children_with_mergeinfo); 8431 8432 /* Determine which subtrees of interest need mergeinfo recorded... */ 8433 SVN_ERR(flag_subtrees_needing_mergeinfo(operative_merge, &range, 8434 children_with_mergeinfo, 8435 mergeinfo_fspath, depth, 8436 merge_b, iterpool)); 8437 8438 /* ...and then record it. */ 8439 for (i = 0; i < children_with_mergeinfo->nelts; i++) 8440 { 8441 const char *child_repos_path; 8442 const char *child_merge_src_fspath; 8443 svn_rangelist_t *child_merge_rangelist; 8444 apr_hash_t *child_merges; 8445 svn_client__merge_path_t *child = 8446 APR_ARRAY_IDX(children_with_mergeinfo, i, 8447 svn_client__merge_path_t *); 8448 SVN_ERR_ASSERT(child); 8449 8450 svn_pool_clear(iterpool); 8451 8452 if (child->record_mergeinfo) 8453 { 8454 child_repos_path = svn_dirent_skip_ancestor(merge_b->target->abspath, 8455 child->abspath); 8456 SVN_ERR_ASSERT(child_repos_path != NULL); 8457 child_merge_src_fspath = svn_fspath__join(mergeinfo_fspath, 8458 child_repos_path, 8459 iterpool); 8460 /* Filter any ranges from each child's natural history before 8461 setting mergeinfo describing the merge. */ 8462 SVN_ERR(filter_natural_history_from_mergeinfo( 8463 &child_merge_rangelist, child_merge_src_fspath, 8464 child->implicit_mergeinfo, &range, iterpool)); 8465 8466 if (child_merge_rangelist->nelts == 0) 8467 continue; 8468 8469 if (!squelch_mergeinfo_notifications) 8470 { 8471 /* If the merge source has a gap, then don't mention 8472 those gap revisions in the notification. */ 8473 remove_source_gap(&range, merge_b->implicit_src_gap); 8474 notify_mergeinfo_recording(child->abspath, &range, 8475 merge_b->ctx, iterpool); 8476 } 8477 8478 /* If we are here we know we will be recording some mergeinfo, but 8479 before we do, set override mergeinfo on skipped paths so they 8480 don't incorrectly inherit the mergeinfo we are about to set. */ 8481 if (i == 0) 8482 SVN_ERR(record_skips_in_mergeinfo(mergeinfo_fspath, 8483 child_merge_rangelist, 8484 is_rollback, merge_b, iterpool)); 8485 8486 /* We may need to record non-inheritable mergeinfo that applies 8487 only to CHILD->ABSPATH. */ 8488 if (child->record_noninheritable) 8489 svn_rangelist__set_inheritance(child_merge_rangelist, FALSE); 8490 8491 /* If CHILD has inherited mergeinfo set it before 8492 recording the first merge range. */ 8493 if (child->inherited_mergeinfo) 8494 SVN_ERR(svn_client__record_wc_mergeinfo( 8495 child->abspath, 8496 child->pre_merge_mergeinfo, 8497 FALSE, merge_b->ctx, 8498 iterpool)); 8499 if (merge_b->implicit_src_gap) 8500 { 8501 /* If this is a reverse merge reorder CHILD->REMAINING_RANGES 8502 so it will work with the svn_rangelist_remove API. */ 8503 if (is_rollback) 8504 SVN_ERR(svn_rangelist_reverse(child_merge_rangelist, 8505 iterpool)); 8506 8507 SVN_ERR(svn_rangelist_remove(&child_merge_rangelist, 8508 merge_b->implicit_src_gap, 8509 child_merge_rangelist, FALSE, 8510 iterpool)); 8511 if (is_rollback) 8512 SVN_ERR(svn_rangelist_reverse(child_merge_rangelist, 8513 iterpool)); 8514 } 8515 8516 child_merges = apr_hash_make(iterpool); 8517 8518 /* The short story: 8519 8520 If we are describing a forward merge, then the naive mergeinfo 8521 defined by MERGE_SOURCE_PATH:MERGED_RANGE->START: 8522 MERGE_SOURCE_PATH:MERGED_RANGE->END may contain non-existent 8523 path-revs or may describe other lines of history. We must 8524 remove these invalid portion(s) before recording mergeinfo 8525 describing the merge. 8526 8527 The long story: 8528 8529 If CHILD is the merge target we know that 8530 MERGE_SOURCE_PATH:MERGED_RANGE->END exists. Further, if there 8531 were no copies in MERGE_SOURCE_PATH's history going back to 8532 RANGE->START then we know that 8533 MERGE_SOURCE_PATH:MERGED_RANGE->START exists too and the two 8534 describe an unbroken line of history, and thus 8535 MERGE_SOURCE_PATH:MERGED_RANGE->START: 8536 MERGE_SOURCE_PATH:MERGED_RANGE->END is a valid description of 8537 the merge -- see normalize_merge_sources() and the global comment 8538 'MERGEINFO MERGE SOURCE NORMALIZATION'. 8539 8540 However, if there *was* a copy, then 8541 MERGE_SOURCE_PATH:MERGED_RANGE->START doesn't exist or is 8542 unrelated to MERGE_SOURCE_PATH:MERGED_RANGE->END. Also, we 8543 don't know if (MERGE_SOURCE_PATH:MERGED_RANGE->START)+1 through 8544 (MERGE_SOURCE_PATH:MERGED_RANGE->END)-1 actually exist. 8545 8546 If CHILD is a subtree of the merge target, then nothing is 8547 guaranteed beyond the fact that MERGE_SOURCE_PATH exists at 8548 MERGED_RANGE->END. */ 8549 if ((!merge_b->record_only || merge_b->reintegrate_merge) 8550 && (!is_rollback)) 8551 { 8552 svn_error_t *err; 8553 svn_mergeinfo_t subtree_history_as_mergeinfo; 8554 svn_rangelist_t *child_merge_src_rangelist; 8555 svn_client__pathrev_t *subtree_mergeinfo_pathrev 8556 = svn_client__pathrev_create_with_relpath( 8557 merge_b->target->loc.repos_root_url, 8558 merge_b->target->loc.repos_uuid, 8559 merged_range->end, child_merge_src_fspath + 1, 8560 iterpool); 8561 8562 /* Confirm that the naive mergeinfo we want to set on 8563 CHILD->ABSPATH both exists and is part of 8564 (MERGE_SOURCE_PATH+CHILD_REPOS_PATH)@MERGED_RANGE->END's 8565 history. */ 8566 /* We know MERGED_RANGE->END is younger than MERGE_RANGE->START 8567 because we only do this for forward merges. */ 8568 err = svn_client__get_history_as_mergeinfo( 8569 &subtree_history_as_mergeinfo, NULL, 8570 subtree_mergeinfo_pathrev, 8571 merged_range->end, merged_range->start, 8572 merge_b->ra_session2, merge_b->ctx, iterpool); 8573 8574 /* If CHILD is a subtree it may have been deleted prior to 8575 MERGED_RANGE->END so the above call to get its history 8576 will fail. */ 8577 if (err) 8578 { 8579 if (err->apr_err != SVN_ERR_FS_NOT_FOUND) 8580 return svn_error_trace(err); 8581 svn_error_clear(err); 8582 } 8583 else 8584 { 8585 child_merge_src_rangelist = svn_hash_gets( 8586 subtree_history_as_mergeinfo, 8587 child_merge_src_fspath); 8588 SVN_ERR(svn_rangelist_intersect(&child_merge_rangelist, 8589 child_merge_rangelist, 8590 child_merge_src_rangelist, 8591 FALSE, iterpool)); 8592 if (child->record_noninheritable) 8593 svn_rangelist__set_inheritance(child_merge_rangelist, 8594 FALSE); 8595 } 8596 } 8597 8598 svn_hash_sets(child_merges, child->abspath, child_merge_rangelist); 8599 SVN_ERR(update_wc_mergeinfo(result_catalog, 8600 child->abspath, 8601 child_merge_src_fspath, 8602 child_merges, is_rollback, 8603 merge_b->ctx, iterpool)); 8604 8605 /* Once is enough: We don't need to record mergeinfo describing 8606 the merge a second. If CHILD->ABSPATH is in 8607 MERGE_B->ADDED_ABSPATHS, we'll do just that, so remove the 8608 former from the latter. */ 8609 svn_hash_sets(merge_b->added_abspaths, child->abspath, NULL); 8610 } 8611 8612 /* Elide explicit subtree mergeinfo whether or not we updated it. */ 8613 if (i > 0) 8614 { 8615 svn_boolean_t in_switched_subtree = FALSE; 8616 8617 if (child->switched) 8618 in_switched_subtree = TRUE; 8619 else if (i > 1) 8620 { 8621 /* Check if CHILD is part of a switched subtree */ 8622 svn_client__merge_path_t *parent; 8623 int j = i - 1; 8624 for (; j > 0; j--) 8625 { 8626 parent = APR_ARRAY_IDX(children_with_mergeinfo, 8627 j, svn_client__merge_path_t *); 8628 if (parent 8629 && parent->switched 8630 && svn_dirent_is_ancestor(parent->abspath, 8631 child->abspath)) 8632 { 8633 in_switched_subtree = TRUE; 8634 break; 8635 } 8636 } 8637 } 8638 8639 /* Allow mergeinfo on switched subtrees to elide to the 8640 repository. Otherwise limit elision to the merge target 8641 for now. do_directory_merge() will eventually try to 8642 elide that when the merge is complete. */ 8643 SVN_ERR(svn_client__elide_mergeinfo( 8644 child->abspath, 8645 in_switched_subtree ? NULL : merge_b->target->abspath, 8646 merge_b->ctx, iterpool)); 8647 } 8648 } /* (i = 0; i < notify_b->children_with_mergeinfo->nelts; i++) */ 8649 8650 svn_pool_destroy(iterpool); 8651 return SVN_NO_ERROR; 8652} 8653 8654/* Helper for do_directory_merge(). 8655 8656 Record mergeinfo describing a merge of 8657 MERGED_RANGE->START:MERGED_RANGE->END from the repository relative path 8658 MERGEINFO_FSPATH to each path in ADDED_ABSPATHS which has explicit 8659 mergeinfo or is the immediate child of a parent with explicit 8660 non-inheritable mergeinfo. 8661 8662 DEPTH, MERGE_B, and SQUELCH_MERGEINFO_NOTIFICATIONS, are 8663 cascaded from do_directory_merge's arguments of the same names. 8664 8665 Note: This is intended to support forward merges only, i.e. 8666 MERGED_RANGE->START must be older than MERGED_RANGE->END. 8667*/ 8668static svn_error_t * 8669record_mergeinfo_for_added_subtrees( 8670 svn_merge_range_t *merged_range, 8671 const char *mergeinfo_fspath, 8672 svn_depth_t depth, 8673 svn_boolean_t squelch_mergeinfo_notifications, 8674 apr_hash_t *added_abspaths, 8675 merge_cmd_baton_t *merge_b, 8676 apr_pool_t *pool) 8677{ 8678 apr_pool_t *iterpool; 8679 apr_hash_index_t *hi; 8680 8681 /* If no paths were added by the merge then we have nothing to do. */ 8682 if (!added_abspaths) 8683 return SVN_NO_ERROR; 8684 8685 SVN_ERR_ASSERT(merged_range->start < merged_range->end); 8686 8687 iterpool = svn_pool_create(pool); 8688 for (hi = apr_hash_first(pool, added_abspaths); hi; hi = apr_hash_next(hi)) 8689 { 8690 const char *added_abspath = svn__apr_hash_index_key(hi); 8691 const char *dir_abspath; 8692 svn_mergeinfo_t parent_mergeinfo; 8693 svn_mergeinfo_t added_path_mergeinfo; 8694 8695 svn_pool_clear(iterpool); 8696 dir_abspath = svn_dirent_dirname(added_abspath, iterpool); 8697 8698 /* Grab the added path's explicit mergeinfo. */ 8699 SVN_ERR(svn_client__get_wc_mergeinfo(&added_path_mergeinfo, NULL, 8700 svn_mergeinfo_explicit, 8701 added_abspath, NULL, NULL, FALSE, 8702 merge_b->ctx, iterpool, iterpool)); 8703 8704 /* If the added path doesn't have explicit mergeinfo, does its immediate 8705 parent have non-inheritable mergeinfo? */ 8706 if (!added_path_mergeinfo) 8707 SVN_ERR(svn_client__get_wc_mergeinfo(&parent_mergeinfo, NULL, 8708 svn_mergeinfo_explicit, 8709 dir_abspath, NULL, NULL, FALSE, 8710 merge_b->ctx, 8711 iterpool, iterpool)); 8712 8713 if (added_path_mergeinfo 8714 || svn_mergeinfo__is_noninheritable(parent_mergeinfo, iterpool)) 8715 { 8716 svn_node_kind_t added_path_kind; 8717 svn_mergeinfo_t merge_mergeinfo; 8718 svn_mergeinfo_t adds_history_as_mergeinfo; 8719 svn_rangelist_t *rangelist; 8720 const char *rel_added_path; 8721 const char *added_path_mergeinfo_fspath; 8722 svn_client__pathrev_t *added_path_pathrev; 8723 8724 SVN_ERR(svn_wc_read_kind2(&added_path_kind, merge_b->ctx->wc_ctx, 8725 added_abspath, FALSE, FALSE, iterpool)); 8726 8727 /* Calculate the naive mergeinfo describing the merge. */ 8728 merge_mergeinfo = apr_hash_make(iterpool); 8729 rangelist = svn_rangelist__initialize( 8730 merged_range->start, merged_range->end, 8731 ((added_path_kind == svn_node_file) 8732 || (!(depth == svn_depth_infinity 8733 || depth == svn_depth_immediates))), 8734 iterpool); 8735 8736 /* Create the new mergeinfo path for added_path's mergeinfo. 8737 (added_abspath had better be a child of MERGE_B->target->abspath 8738 or something is *really* wrong.) */ 8739 rel_added_path = svn_dirent_is_child(merge_b->target->abspath, 8740 added_abspath, iterpool); 8741 SVN_ERR_ASSERT(rel_added_path); 8742 added_path_mergeinfo_fspath = svn_fspath__join(mergeinfo_fspath, 8743 rel_added_path, 8744 iterpool); 8745 svn_hash_sets(merge_mergeinfo, added_path_mergeinfo_fspath, 8746 rangelist); 8747 8748 /* Don't add new mergeinfo to describe the merge if that mergeinfo 8749 contains non-existent merge sources. 8750 8751 We know that MERGEINFO_PATH/rel_added_path's history does not 8752 span MERGED_RANGE->START:MERGED_RANGE->END but rather that it 8753 was added at some revions greater than MERGED_RANGE->START 8754 (assuming this is a forward merge). It may have been added, 8755 deleted, and re-added many times. The point is that we cannot 8756 blindly apply the naive mergeinfo calculated above because it 8757 will describe non-existent merge sources. To avoid this we get 8758 take the intersection of the naive mergeinfo with 8759 MERGEINFO_PATH/rel_added_path's history. */ 8760 added_path_pathrev = svn_client__pathrev_create_with_relpath( 8761 merge_b->target->loc.repos_root_url, 8762 merge_b->target->loc.repos_uuid, 8763 MAX(merged_range->start, merged_range->end), 8764 added_path_mergeinfo_fspath + 1, iterpool); 8765 SVN_ERR(svn_client__get_history_as_mergeinfo( 8766 &adds_history_as_mergeinfo, NULL, 8767 added_path_pathrev, 8768 MAX(merged_range->start, merged_range->end), 8769 MIN(merged_range->start, merged_range->end), 8770 merge_b->ra_session2, merge_b->ctx, iterpool)); 8771 8772 SVN_ERR(svn_mergeinfo_intersect2(&merge_mergeinfo, 8773 merge_mergeinfo, 8774 adds_history_as_mergeinfo, 8775 FALSE, iterpool, iterpool)); 8776 8777 /* Combine the explicit mergeinfo on the added path (if any) 8778 with the mergeinfo describing this merge. */ 8779 if (added_path_mergeinfo) 8780 SVN_ERR(svn_mergeinfo_merge2(merge_mergeinfo, 8781 added_path_mergeinfo, 8782 iterpool, iterpool)); 8783 SVN_ERR(svn_client__record_wc_mergeinfo( 8784 added_abspath, merge_mergeinfo, 8785 !squelch_mergeinfo_notifications, merge_b->ctx, iterpool)); 8786 } 8787 } 8788 svn_pool_destroy(iterpool); 8789 8790 return SVN_NO_ERROR; 8791} 8792/* Baton structure for log_noop_revs. */ 8793typedef struct log_noop_baton_t 8794{ 8795 /* See the comment 'THE CHILDREN_WITH_MERGEINFO ARRAY' at the start 8796 of this file.*/ 8797 apr_array_header_t *children_with_mergeinfo; 8798 8799 /* Absolute repository path of younger of the two merge sources 8800 being diffed. */ 8801 const char *source_fspath; 8802 8803 /* The merge target. */ 8804 const merge_target_t *target; 8805 8806 /* Initially empty rangelists allocated in POOL. The rangelists are 8807 * populated across multiple invocations of log_noop_revs(). */ 8808 svn_rangelist_t *operative_ranges; 8809 svn_rangelist_t *merged_ranges; 8810 8811 /* Pool to store the rangelists. */ 8812 apr_pool_t *pool; 8813} log_noop_baton_t; 8814 8815/* Helper for log_noop_revs: Merge a svn_merge_range_t representation of 8816 REVISION into RANGELIST. New elements added to rangelist are allocated 8817 in RESULT_POOL. 8818 8819 This is *not* a general purpose rangelist merge but a special replacement 8820 for svn_rangelist_merge when REVISION is guaranteed to be younger than any 8821 element in RANGELIST. svn_rangelist_merge is O(n) worst-case (i.e. when 8822 all the ranges in output rangelist are older than the incoming changes). 8823 This turns the special case of a single incoming younger range into O(1). 8824 */ 8825static svn_error_t * 8826rangelist_merge_revision(svn_rangelist_t *rangelist, 8827 svn_revnum_t revision, 8828 apr_pool_t *result_pool) 8829{ 8830 svn_merge_range_t *new_range; 8831 if (rangelist->nelts) 8832 { 8833 svn_merge_range_t *range = APR_ARRAY_IDX(rangelist, rangelist->nelts - 1, 8834 svn_merge_range_t *); 8835 if (range->end == revision - 1) 8836 { 8837 /* REVISION is adjacent to the youngest range in RANGELIST 8838 so we can simply expand that range to encompass REVISION. */ 8839 range->end = revision; 8840 return SVN_NO_ERROR; 8841 } 8842 } 8843 new_range = apr_palloc(result_pool, sizeof(*new_range)); 8844 new_range->start = revision - 1; 8845 new_range->end = revision; 8846 new_range->inheritable = TRUE; 8847 8848 APR_ARRAY_PUSH(rangelist, svn_merge_range_t *) = new_range; 8849 8850 return SVN_NO_ERROR; 8851} 8852 8853/* Implements the svn_log_entry_receiver_t interface. 8854 8855 BATON is an log_noop_baton_t *. 8856 8857 Add LOG_ENTRY->REVISION to BATON->OPERATIVE_RANGES. 8858 8859 If LOG_ENTRY->REVISION has already been fully merged to 8860 BATON->target->abspath per the mergeinfo in BATON->CHILDREN_WITH_MERGEINFO, 8861 then add LOG_ENTRY->REVISION to BATON->MERGED_RANGES. 8862 8863 Use SCRATCH_POOL for temporary allocations. Allocate additions to 8864 BATON->MERGED_RANGES and BATON->OPERATIVE_RANGES in BATON->POOL. 8865 8866 Note: This callback must be invoked from oldest LOG_ENTRY->REVISION 8867 to youngest LOG_ENTRY->REVISION -- see rangelist_merge_revision(). 8868*/ 8869static svn_error_t * 8870log_noop_revs(void *baton, 8871 svn_log_entry_t *log_entry, 8872 apr_pool_t *scratch_pool) 8873{ 8874 log_noop_baton_t *log_gap_baton = baton; 8875 apr_hash_index_t *hi; 8876 svn_revnum_t revision; 8877 svn_boolean_t log_entry_rev_required = FALSE; 8878 8879 revision = log_entry->revision; 8880 8881 /* It's possible that authz restrictions on the merge source prevent us 8882 from knowing about any of the changes for LOG_ENTRY->REVISION. */ 8883 if (!log_entry->changed_paths2) 8884 return SVN_NO_ERROR; 8885 8886 /* Unconditionally add LOG_ENTRY->REVISION to BATON->OPERATIVE_MERGES. */ 8887 SVN_ERR(rangelist_merge_revision(log_gap_baton->operative_ranges, 8888 revision, 8889 log_gap_baton->pool)); 8890 8891 /* Examine each path affected by LOG_ENTRY->REVISION. If the explicit or 8892 inherited mergeinfo for *all* of the corresponding paths under 8893 BATON->target->abspath reflects that LOG_ENTRY->REVISION has been 8894 merged, then add LOG_ENTRY->REVISION to BATON->MERGED_RANGES. */ 8895 for (hi = apr_hash_first(scratch_pool, log_entry->changed_paths2); 8896 hi; 8897 hi = apr_hash_next(hi)) 8898 { 8899 const char *fspath = svn__apr_hash_index_key(hi); 8900 const char *rel_path; 8901 const char *cwmi_abspath; 8902 svn_rangelist_t *paths_explicit_rangelist = NULL; 8903 svn_boolean_t mergeinfo_inherited = FALSE; 8904 8905 /* Adjust REL_PATH so it is relative to the merge source then use it to 8906 calculate what path in the merge target would be affected by this 8907 revision. */ 8908 rel_path = svn_fspath__skip_ancestor(log_gap_baton->source_fspath, 8909 fspath); 8910 /* Is PATH even within the merge target? If it isn't we 8911 can disregard it altogether. */ 8912 if (rel_path == NULL) 8913 continue; 8914 cwmi_abspath = svn_dirent_join(log_gap_baton->target->abspath, 8915 rel_path, scratch_pool); 8916 8917 /* Find any explicit or inherited mergeinfo for PATH. */ 8918 while (!log_entry_rev_required) 8919 { 8920 svn_client__merge_path_t *child = get_child_with_mergeinfo( 8921 log_gap_baton->children_with_mergeinfo, cwmi_abspath); 8922 8923 if (child && child->pre_merge_mergeinfo) 8924 { 8925 /* Found some explicit mergeinfo, grab any ranges 8926 for PATH. */ 8927 paths_explicit_rangelist = 8928 svn_hash_gets(child->pre_merge_mergeinfo, fspath); 8929 break; 8930 } 8931 8932 if (cwmi_abspath[0] == '\0' 8933 || svn_dirent_is_root(cwmi_abspath, strlen(cwmi_abspath)) 8934 || strcmp(log_gap_baton->target->abspath, cwmi_abspath) == 0) 8935 { 8936 /* Can't crawl any higher. */ 8937 break; 8938 } 8939 8940 /* Didn't find anything so crawl up to the parent. */ 8941 cwmi_abspath = svn_dirent_dirname(cwmi_abspath, scratch_pool); 8942 fspath = svn_fspath__dirname(fspath, scratch_pool); 8943 8944 /* At this point *if* we find mergeinfo it will be inherited. */ 8945 mergeinfo_inherited = TRUE; 8946 } 8947 8948 if (paths_explicit_rangelist) 8949 { 8950 svn_rangelist_t *intersecting_range; 8951 svn_rangelist_t *rangelist; 8952 8953 rangelist = svn_rangelist__initialize(revision - 1, revision, TRUE, 8954 scratch_pool); 8955 8956 /* If PATH inherited mergeinfo we must consider inheritance in the 8957 event the inherited mergeinfo is actually non-inheritable. */ 8958 SVN_ERR(svn_rangelist_intersect(&intersecting_range, 8959 paths_explicit_rangelist, 8960 rangelist, 8961 mergeinfo_inherited, scratch_pool)); 8962 8963 if (intersecting_range->nelts == 0) 8964 log_entry_rev_required = TRUE; 8965 } 8966 else 8967 { 8968 log_entry_rev_required = TRUE; 8969 } 8970 } 8971 8972 if (!log_entry_rev_required) 8973 SVN_ERR(rangelist_merge_revision(log_gap_baton->merged_ranges, 8974 revision, 8975 log_gap_baton->pool)); 8976 8977 return SVN_NO_ERROR; 8978} 8979 8980/* Helper for do_directory_merge(). 8981 8982 SOURCE is cascaded from the argument of the same name in 8983 do_directory_merge(). TARGET is the merge target. RA_SESSION is the 8984 session for SOURCE->loc2. 8985 8986 Find all the ranges required by subtrees in 8987 CHILDREN_WITH_MERGEINFO that are *not* required by 8988 TARGET->abspath (i.e. CHILDREN_WITH_MERGEINFO[0]). If such 8989 ranges exist, then find any subset of ranges which, if merged, would be 8990 inoperative. Finally, if any inoperative ranges are found then remove 8991 these ranges from all of the subtree's REMAINING_RANGES. 8992 8993 This function should only be called when honoring mergeinfo during 8994 forward merges (i.e. SOURCE->rev1 < SOURCE->rev2). 8995*/ 8996static svn_error_t * 8997remove_noop_subtree_ranges(const merge_source_t *source, 8998 const merge_target_t *target, 8999 svn_ra_session_t *ra_session, 9000 apr_array_header_t *children_with_mergeinfo, 9001 apr_pool_t *result_pool, 9002 apr_pool_t *scratch_pool) 9003{ 9004 /* ### Do we need to check that we are at a uniform working revision? */ 9005 int i; 9006 svn_client__merge_path_t *root_child = 9007 APR_ARRAY_IDX(children_with_mergeinfo, 0, svn_client__merge_path_t *); 9008 svn_rangelist_t *requested_ranges; 9009 svn_rangelist_t *subtree_gap_ranges; 9010 svn_rangelist_t *subtree_remaining_ranges; 9011 log_noop_baton_t log_gap_baton; 9012 svn_merge_range_t *oldest_gap_rev; 9013 svn_merge_range_t *youngest_gap_rev; 9014 svn_rangelist_t *inoperative_ranges; 9015 apr_pool_t *iterpool; 9016 const char *longest_common_subtree_ancestor = NULL; 9017 svn_error_t *err; 9018 9019 assert(session_url_is(ra_session, source->loc2->url, scratch_pool)); 9020 9021 /* This function is only intended to work with forward merges. */ 9022 if (source->loc1->rev > source->loc2->rev) 9023 return SVN_NO_ERROR; 9024 9025 /* Another easy out: There are no subtrees. */ 9026 if (children_with_mergeinfo->nelts < 2) 9027 return SVN_NO_ERROR; 9028 9029 subtree_remaining_ranges = apr_array_make(scratch_pool, 1, 9030 sizeof(svn_merge_range_t *)); 9031 9032 /* Given the requested merge of SOURCE->rev1:rev2 might there be any 9033 part of this range required for subtrees but not for the target? */ 9034 requested_ranges = svn_rangelist__initialize(MIN(source->loc1->rev, 9035 source->loc2->rev), 9036 MAX(source->loc1->rev, 9037 source->loc2->rev), 9038 TRUE, scratch_pool); 9039 SVN_ERR(svn_rangelist_remove(&subtree_gap_ranges, 9040 root_child->remaining_ranges, 9041 requested_ranges, FALSE, scratch_pool)); 9042 9043 /* Early out, nothing to operate on */ 9044 if (!subtree_gap_ranges->nelts) 9045 return SVN_NO_ERROR; 9046 9047 /* Create a rangelist describing every range required across all subtrees. */ 9048 iterpool = svn_pool_create(scratch_pool); 9049 for (i = 1; i < children_with_mergeinfo->nelts; i++) 9050 { 9051 svn_client__merge_path_t *child = 9052 APR_ARRAY_IDX(children_with_mergeinfo, i, svn_client__merge_path_t *); 9053 9054 svn_pool_clear(iterpool); 9055 9056 /* Issue #4269: Keep track of the longest common ancestor of all the 9057 subtrees which require merges. This may be a child of 9058 TARGET->ABSPATH, which will allow us to narrow the log request 9059 below. */ 9060 if (child->remaining_ranges && child->remaining_ranges->nelts) 9061 { 9062 if (longest_common_subtree_ancestor) 9063 longest_common_subtree_ancestor = svn_dirent_get_longest_ancestor( 9064 longest_common_subtree_ancestor, child->abspath, scratch_pool); 9065 else 9066 longest_common_subtree_ancestor = child->abspath; 9067 } 9068 9069 /* CHILD->REMAINING_RANGES will be NULL if child is absent. */ 9070 if (child->remaining_ranges && child->remaining_ranges->nelts) 9071 SVN_ERR(svn_rangelist_merge2(subtree_remaining_ranges, 9072 child->remaining_ranges, 9073 scratch_pool, iterpool)); 9074 } 9075 svn_pool_destroy(iterpool); 9076 9077 /* It's possible that none of the subtrees had any remaining ranges. */ 9078 if (!subtree_remaining_ranges->nelts) 9079 return SVN_NO_ERROR; 9080 9081 /* Ok, *finally* we can answer what part(s) of SOURCE->rev1:rev2 are 9082 required for the subtrees but not the target. */ 9083 SVN_ERR(svn_rangelist_intersect(&subtree_gap_ranges, 9084 subtree_gap_ranges, 9085 subtree_remaining_ranges, FALSE, 9086 scratch_pool)); 9087 9088 /* Another early out */ 9089 if (!subtree_gap_ranges->nelts) 9090 return SVN_NO_ERROR; 9091 9092 /* One or more subtrees need some revisions that the target doesn't need. 9093 Use log to determine if any of these revisions are inoperative. */ 9094 oldest_gap_rev = APR_ARRAY_IDX(subtree_gap_ranges, 0, svn_merge_range_t *); 9095 youngest_gap_rev = APR_ARRAY_IDX(subtree_gap_ranges, 9096 subtree_gap_ranges->nelts - 1, svn_merge_range_t *); 9097 9098 /* Set up the log baton. */ 9099 log_gap_baton.children_with_mergeinfo = children_with_mergeinfo; 9100 log_gap_baton.source_fspath 9101 = svn_client__pathrev_fspath(source->loc2, result_pool); 9102 log_gap_baton.target = target; 9103 log_gap_baton.merged_ranges = apr_array_make(scratch_pool, 0, 9104 sizeof(svn_revnum_t *)); 9105 log_gap_baton.operative_ranges = apr_array_make(scratch_pool, 0, 9106 sizeof(svn_revnum_t *)); 9107 log_gap_baton.pool = svn_pool_create(scratch_pool); 9108 9109 /* Find the longest common ancestor of all subtrees relative to 9110 RA_SESSION's URL. */ 9111 if (longest_common_subtree_ancestor) 9112 longest_common_subtree_ancestor = 9113 svn_dirent_skip_ancestor(target->abspath, 9114 longest_common_subtree_ancestor); 9115 else 9116 longest_common_subtree_ancestor = ""; 9117 9118 /* Invoke the svn_log_entry_receiver_t receiver log_noop_revs() from 9119 oldest to youngest. The receiver is optimized to add ranges to 9120 log_gap_baton.merged_ranges and log_gap_baton.operative_ranges, but 9121 requires that the revs arrive oldest to youngest -- see log_noop_revs() 9122 and rangelist_merge_revision(). */ 9123 err = get_log(ra_session, longest_common_subtree_ancestor, 9124 oldest_gap_rev->start + 1, youngest_gap_rev->end, TRUE, 9125 log_noop_revs, &log_gap_baton, scratch_pool); 9126 9127 /* It's possible that the only subtrees with mergeinfo in TARGET don't have 9128 any corresponding subtree in SOURCE between SOURCE->REV1 < SOURCE->REV2. 9129 So it's also possible that we may ask for the logs of non-existent paths. 9130 If we do, then assume that no subtree requires any ranges that are not 9131 already required by the TARGET. */ 9132 if (err) 9133 { 9134 if (err->apr_err != SVN_ERR_FS_NOT_FOUND 9135 && longest_common_subtree_ancestor[0] != '\0') 9136 return svn_error_trace(err); 9137 9138 /* Asked about a non-existent subtree in SOURCE. */ 9139 svn_error_clear(err); 9140 log_gap_baton.merged_ranges = 9141 svn_rangelist__initialize(oldest_gap_rev->start, 9142 youngest_gap_rev->end, 9143 TRUE, scratch_pool); 9144 } 9145 else 9146 { 9147 inoperative_ranges = svn_rangelist__initialize(oldest_gap_rev->start, 9148 youngest_gap_rev->end, 9149 TRUE, scratch_pool); 9150 SVN_ERR(svn_rangelist_remove(&(inoperative_ranges), 9151 log_gap_baton.operative_ranges, 9152 inoperative_ranges, FALSE, scratch_pool)); 9153 SVN_ERR(svn_rangelist_merge2(log_gap_baton.merged_ranges, inoperative_ranges, 9154 scratch_pool, scratch_pool)); 9155 } 9156 9157 for (i = 1; i < children_with_mergeinfo->nelts; i++) 9158 { 9159 svn_client__merge_path_t *child = 9160 APR_ARRAY_IDX(children_with_mergeinfo, i, svn_client__merge_path_t *); 9161 9162 /* CHILD->REMAINING_RANGES will be NULL if child is absent. */ 9163 if (child->remaining_ranges && child->remaining_ranges->nelts) 9164 { 9165 /* Remove inoperative ranges from all children so we don't perform 9166 inoperative editor drives. */ 9167 SVN_ERR(svn_rangelist_remove(&(child->remaining_ranges), 9168 log_gap_baton.merged_ranges, 9169 child->remaining_ranges, 9170 FALSE, result_pool)); 9171 } 9172 } 9173 9174 svn_pool_destroy(log_gap_baton.pool); 9175 9176 return SVN_NO_ERROR; 9177} 9178 9179/* Perform a merge of changes in SOURCE to the working copy path 9180 TARGET_ABSPATH. Both URLs in SOURCE, and TARGET_ABSPATH all represent 9181 directories -- for the single file case, the caller should use 9182 do_file_merge(). 9183 9184 CHILDREN_WITH_MERGEINFO and MERGE_B describe the merge being performed 9185 As this function is for a mergeinfo-aware merge, SOURCE->ancestral 9186 should be TRUE, and SOURCE->loc1 must be a historical ancestor of 9187 SOURCE->loc2, or vice-versa (see `MERGEINFO MERGE SOURCE NORMALIZATION' 9188 for more requirements around SOURCE). 9189 9190 Mergeinfo changes will be recorded unless MERGE_B->dry_run is true. 9191 9192 If mergeinfo is being recorded, SQUELCH_MERGEINFO_NOTIFICATIONS is FALSE, 9193 and MERGE_B->CTX->NOTIFY_FUNC2 is not NULL, then call 9194 MERGE_B->CTX->NOTIFY_FUNC2 with MERGE_B->CTX->NOTIFY_BATON2 and a 9195 svn_wc_notify_merge_record_info_begin notification before any mergeinfo 9196 changes are made to describe the merge performed. 9197 9198 If mergeinfo is being recorded to describe this merge, and RESULT_CATALOG 9199 is not NULL, then don't record the new mergeinfo on the WC, but instead 9200 record it in RESULT_CATALOG, where the keys are absolute working copy 9201 paths and the values are the new mergeinfos for each. Allocate additions 9202 to RESULT_CATALOG in pool which RESULT_CATALOG was created in. 9203 9204 Handle DEPTH as documented for svn_client_merge5(). 9205 9206 CONFLICT_REPORT is as documented for do_directory_merge(). 9207 9208 Perform any temporary allocations in SCRATCH_POOL. 9209 9210 NOTE: This is a wrapper around drive_merge_report_editor() which 9211 handles the complexities inherent to situations where a given 9212 directory's children may have intersecting merges (because they 9213 meet one or more of the criteria described in get_mergeinfo_paths()). 9214*/ 9215static svn_error_t * 9216do_mergeinfo_aware_dir_merge(svn_mergeinfo_catalog_t result_catalog, 9217 single_range_conflict_report_t **conflict_report, 9218 const merge_source_t *source, 9219 const char *target_abspath, 9220 apr_array_header_t *children_with_mergeinfo, 9221 const svn_diff_tree_processor_t *processor, 9222 svn_depth_t depth, 9223 svn_boolean_t squelch_mergeinfo_notifications, 9224 merge_cmd_baton_t *merge_b, 9225 apr_pool_t *result_pool, 9226 apr_pool_t *scratch_pool) 9227{ 9228 /* The range defining the mergeinfo we will record to describe the merge 9229 (assuming we are recording mergeinfo 9230 9231 Note: This may be a subset of SOURCE->rev1:rev2 if 9232 populate_remaining_ranges() determines that some part of 9233 SOURCE->rev1:rev2 has already been wholly merged to TARGET_ABSPATH. 9234 Also, the actual editor drive(s) may be a subset of RANGE, if 9235 remove_noop_subtree_ranges() and/or fix_deleted_subtree_ranges() 9236 further tweak things. */ 9237 svn_merge_range_t range; 9238 9239 svn_ra_session_t *ra_session; 9240 svn_client__merge_path_t *target_merge_path; 9241 svn_boolean_t is_rollback = (source->loc1->rev > source->loc2->rev); 9242 9243 SVN_ERR_ASSERT(source->ancestral); 9244 9245 /*** If we get here, we're dealing with related sources from the 9246 same repository as the target -- merge tracking might be 9247 happenin'! ***/ 9248 9249 *conflict_report = NULL; 9250 9251 /* Point our RA_SESSION to the URL of our youngest merge source side. */ 9252 ra_session = is_rollback ? merge_b->ra_session1 : merge_b->ra_session2; 9253 9254 /* Fill NOTIFY_B->CHILDREN_WITH_MERGEINFO with child paths (const 9255 svn_client__merge_path_t *) which might have intersecting merges 9256 because they meet one or more of the criteria described in 9257 get_mergeinfo_paths(). Here the paths are arranged in a depth 9258 first order. */ 9259 SVN_ERR(get_mergeinfo_paths(children_with_mergeinfo, 9260 merge_b->target, depth, 9261 merge_b->dry_run, merge_b->same_repos, 9262 merge_b->ctx, scratch_pool, scratch_pool)); 9263 9264 /* The first item from the NOTIFY_B->CHILDREN_WITH_MERGEINFO is always 9265 the target thanks to depth-first ordering. */ 9266 target_merge_path = APR_ARRAY_IDX(children_with_mergeinfo, 0, 9267 svn_client__merge_path_t *); 9268 9269 /* If we are honoring mergeinfo, then for each item in 9270 NOTIFY_B->CHILDREN_WITH_MERGEINFO, we need to calculate what needs to be 9271 merged, and then merge it. Otherwise, we just merge what we were asked 9272 to merge across the whole tree. */ 9273 SVN_ERR(populate_remaining_ranges(children_with_mergeinfo, 9274 source, ra_session, 9275 merge_b, scratch_pool, scratch_pool)); 9276 9277 /* Always start with a range which describes the most inclusive merge 9278 possible, i.e. SOURCE->rev1:rev2. */ 9279 range.start = source->loc1->rev; 9280 range.end = source->loc2->rev; 9281 range.inheritable = TRUE; 9282 9283 if (!merge_b->reintegrate_merge) 9284 { 9285 svn_revnum_t new_range_start, start_rev; 9286 apr_pool_t *iterpool = svn_pool_create(scratch_pool); 9287 9288 /* The merge target TARGET_ABSPATH and/or its subtrees may not need all 9289 of SOURCE->rev1:rev2 applied. So examine 9290 NOTIFY_B->CHILDREN_WITH_MERGEINFO to find the oldest starting 9291 revision that actually needs to be merged (for reverse merges this is 9292 the youngest starting revision). 9293 9294 We'll do this twice, right now for the start of the mergeinfo we will 9295 ultimately record to describe this merge and then later for the 9296 start of the actual editor drive. */ 9297 new_range_start = get_most_inclusive_rev( 9298 children_with_mergeinfo, is_rollback, TRUE); 9299 if (SVN_IS_VALID_REVNUM(new_range_start)) 9300 range.start = new_range_start; 9301 9302 /* Remove inoperative ranges from any subtrees' remaining_ranges 9303 to spare the expense of noop editor drives. */ 9304 if (!is_rollback) 9305 SVN_ERR(remove_noop_subtree_ranges(source, merge_b->target, 9306 ra_session, 9307 children_with_mergeinfo, 9308 scratch_pool, iterpool)); 9309 9310 /* Adjust subtrees' remaining_ranges to deal with issue #3067: 9311 * "subtrees that don't exist at the start or end of a merge range 9312 * shouldn't break the merge". */ 9313 SVN_ERR(fix_deleted_subtree_ranges(source, merge_b->target, 9314 ra_session, 9315 children_with_mergeinfo, 9316 merge_b->ctx, scratch_pool, iterpool)); 9317 9318 /* remove_noop_subtree_ranges() and/or fix_deleted_subtree_range() 9319 may have further refined the starting revision for our editor 9320 drive. */ 9321 start_rev = 9322 get_most_inclusive_rev(children_with_mergeinfo, 9323 is_rollback, TRUE); 9324 9325 /* Is there anything to merge? */ 9326 if (SVN_IS_VALID_REVNUM(start_rev)) 9327 { 9328 /* Now examine NOTIFY_B->CHILDREN_WITH_MERGEINFO to find the oldest 9329 ending revision that actually needs to be merged (for reverse 9330 merges this is the youngest ending revision). */ 9331 svn_revnum_t end_rev = 9332 get_most_inclusive_rev(children_with_mergeinfo, 9333 is_rollback, FALSE); 9334 9335 /* While END_REV is valid, do the following: 9336 9337 1. Tweak each NOTIFY_B->CHILDREN_WITH_MERGEINFO element so that 9338 the element's remaining_ranges member has as its first element 9339 a range that ends with end_rev. 9340 9341 2. Starting with start_rev, call drive_merge_report_editor() 9342 on MERGE_B->target->abspath for start_rev:end_rev. 9343 9344 3. Remove the first element from each 9345 NOTIFY_B->CHILDREN_WITH_MERGEINFO element's remaining_ranges 9346 member. 9347 9348 4. Again examine NOTIFY_B->CHILDREN_WITH_MERGEINFO to find the most 9349 inclusive starting revision that actually needs to be merged and 9350 update start_rev. This prevents us from needlessly contacting the 9351 repository and doing a diff where we describe the entire target 9352 tree as *not* needing any of the requested range. This can happen 9353 whenever we have mergeinfo with gaps in it for the merge source. 9354 9355 5. Again examine NOTIFY_B->CHILDREN_WITH_MERGEINFO to find the most 9356 inclusive ending revision that actually needs to be merged and 9357 update end_rev. 9358 9359 6. Lather, rinse, repeat. 9360 */ 9361 9362 while (end_rev != SVN_INVALID_REVNUM) 9363 { 9364 merge_source_t *real_source; 9365 svn_merge_range_t *first_target_range 9366 = (target_merge_path->remaining_ranges->nelts == 0 ? NULL 9367 : APR_ARRAY_IDX(target_merge_path->remaining_ranges, 0, 9368 svn_merge_range_t *)); 9369 9370 /* Issue #3324: Stop editor abuse! Don't call 9371 drive_merge_report_editor() in such a way that we request an 9372 editor with svn_client__get_diff_editor() for some rev X, 9373 then call svn_ra_do_diff3() for some revision Y, and then 9374 call reporter->set_path(PATH=="") to set the root revision 9375 for the editor drive to revision Z where 9376 (X != Z && X < Z < Y). This is bogus because the server will 9377 send us the diff between X:Y but the client is expecting the 9378 diff between Y:Z. See issue #3324 for full details on the 9379 problems this can cause. */ 9380 if (first_target_range 9381 && start_rev != first_target_range->start) 9382 { 9383 if (is_rollback) 9384 { 9385 if (end_rev < first_target_range->start) 9386 end_rev = first_target_range->start; 9387 } 9388 else 9389 { 9390 if (end_rev > first_target_range->start) 9391 end_rev = first_target_range->start; 9392 } 9393 } 9394 9395 svn_pool_clear(iterpool); 9396 9397 slice_remaining_ranges(children_with_mergeinfo, 9398 is_rollback, end_rev, scratch_pool); 9399 9400 /* Reset variables that must be reset for every drive */ 9401 merge_b->notify_begin.last_abspath = NULL; 9402 9403 real_source = subrange_source(source, start_rev, end_rev, iterpool); 9404 SVN_ERR(drive_merge_report_editor( 9405 merge_b->target->abspath, 9406 real_source, 9407 children_with_mergeinfo, 9408 processor, 9409 depth, 9410 merge_b, 9411 iterpool)); 9412 9413 /* If any paths picked up explicit mergeinfo as a result of 9414 the merge we need to make sure any mergeinfo those paths 9415 inherited is recorded and then add these paths to 9416 NOTIFY_B->CHILDREN_WITH_MERGEINFO.*/ 9417 SVN_ERR(process_children_with_new_mergeinfo( 9418 merge_b, children_with_mergeinfo, 9419 scratch_pool)); 9420 9421 /* If any subtrees had their explicit mergeinfo deleted as a 9422 result of the merge then remove these paths from 9423 NOTIFY_B->CHILDREN_WITH_MERGEINFO since there is no need 9424 to consider these subtrees for subsequent editor drives 9425 nor do we want to record mergeinfo on them describing 9426 the merge itself. */ 9427 remove_children_with_deleted_mergeinfo( 9428 merge_b, children_with_mergeinfo); 9429 9430 /* Prepare for the next iteration (if any). */ 9431 remove_first_range_from_remaining_ranges( 9432 end_rev, children_with_mergeinfo, scratch_pool); 9433 9434 /* If we raised any conflicts, break out and report how much 9435 we have merged. */ 9436 if (is_path_conflicted_by_merge(merge_b)) 9437 { 9438 merge_source_t *remaining_range = NULL; 9439 9440 if (real_source->loc2->rev != source->loc2->rev) 9441 remaining_range = subrange_source(source, 9442 real_source->loc2->rev, 9443 source->loc2->rev, 9444 scratch_pool); 9445 *conflict_report = single_range_conflict_report_create( 9446 real_source, remaining_range, 9447 result_pool); 9448 9449 range.end = end_rev; 9450 break; 9451 } 9452 9453 start_rev = 9454 get_most_inclusive_rev(children_with_mergeinfo, 9455 is_rollback, TRUE); 9456 end_rev = 9457 get_most_inclusive_rev(children_with_mergeinfo, 9458 is_rollback, FALSE); 9459 } 9460 } 9461 svn_pool_destroy(iterpool); 9462 } 9463 else 9464 { 9465 if (!merge_b->record_only) 9466 { 9467 /* Reset cur_ancestor_abspath to null so that subsequent cherry 9468 picked revision ranges will be notified upon subsequent 9469 operative merge. */ 9470 merge_b->notify_begin.last_abspath = NULL; 9471 9472 SVN_ERR(drive_merge_report_editor(merge_b->target->abspath, 9473 source, 9474 NULL, 9475 processor, 9476 depth, 9477 merge_b, 9478 scratch_pool)); 9479 } 9480 } 9481 9482 /* Record mergeinfo where appropriate.*/ 9483 if (RECORD_MERGEINFO(merge_b)) 9484 { 9485 const svn_client__pathrev_t *primary_src 9486 = is_rollback ? source->loc1 : source->loc2; 9487 const char *mergeinfo_path 9488 = svn_client__pathrev_fspath(primary_src, scratch_pool); 9489 9490 SVN_ERR(record_mergeinfo_for_dir_merge(result_catalog, 9491 &range, 9492 mergeinfo_path, 9493 children_with_mergeinfo, 9494 depth, 9495 squelch_mergeinfo_notifications, 9496 merge_b, 9497 scratch_pool)); 9498 9499 /* If a path has an immediate parent with non-inheritable mergeinfo at 9500 this point, then it meets criteria 3 or 5 described in 9501 get_mergeinfo_paths' doc string. For paths which exist prior to a 9502 merge explicit mergeinfo has already been set. But for paths added 9503 during the merge this is not the case. The path might have explicit 9504 mergeinfo from the merge source, but no mergeinfo yet exists 9505 describing *this* merge. So the added path has either incomplete 9506 explicit mergeinfo or inherits incomplete mergeinfo from its 9507 immediate parent (if any, the parent might have only non-inheritable 9508 ranges in which case the path simply inherits empty mergeinfo). 9509 9510 So here we look at the root path of each subtree added during the 9511 merge and set explicit mergeinfo on it if it meets the aforementioned 9512 conditions. */ 9513 if (range.start < range.end) /* Nothing to record on added subtrees 9514 resulting from reverse merges. */ 9515 { 9516 SVN_ERR(record_mergeinfo_for_added_subtrees( 9517 &range, mergeinfo_path, depth, 9518 squelch_mergeinfo_notifications, 9519 merge_b->added_abspaths, merge_b, scratch_pool)); 9520 } 9521 } 9522 9523 return SVN_NO_ERROR; 9524} 9525 9526/* Helper for do_merge() when the merge target is a directory. 9527 * 9528 * If any conflict is raised during the merge, set *CONFLICTED_RANGE to 9529 * the revision sub-range that raised the conflict. In this case, the 9530 * merge will have ended at revision CONFLICTED_RANGE and mergeinfo will 9531 * have been recorded for all revision sub-ranges up to and including 9532 * CONFLICTED_RANGE. Otherwise, set *CONFLICTED_RANGE to NULL. 9533 */ 9534static svn_error_t * 9535do_directory_merge(svn_mergeinfo_catalog_t result_catalog, 9536 single_range_conflict_report_t **conflict_report, 9537 const merge_source_t *source, 9538 const char *target_abspath, 9539 const svn_diff_tree_processor_t *processor, 9540 svn_depth_t depth, 9541 svn_boolean_t squelch_mergeinfo_notifications, 9542 merge_cmd_baton_t *merge_b, 9543 apr_pool_t *result_pool, 9544 apr_pool_t *scratch_pool) 9545{ 9546 apr_array_header_t *children_with_mergeinfo; 9547 9548 /* Initialize CHILDREN_WITH_MERGEINFO. See the comment 9549 'THE CHILDREN_WITH_MERGEINFO ARRAY' at the start of this file. */ 9550 children_with_mergeinfo = 9551 apr_array_make(scratch_pool, 16, sizeof(svn_client__merge_path_t *)); 9552 9553 /* And make it read-only accessible from the baton */ 9554 merge_b->notify_begin.nodes_with_mergeinfo = children_with_mergeinfo; 9555 9556 /* If we are not honoring mergeinfo we can skip right to the 9557 business of merging changes! */ 9558 if (HONOR_MERGEINFO(merge_b)) 9559 SVN_ERR(do_mergeinfo_aware_dir_merge(result_catalog, conflict_report, 9560 source, target_abspath, 9561 children_with_mergeinfo, 9562 processor, depth, 9563 squelch_mergeinfo_notifications, 9564 merge_b, result_pool, scratch_pool)); 9565 else 9566 SVN_ERR(do_mergeinfo_unaware_dir_merge(conflict_report, 9567 source, target_abspath, 9568 children_with_mergeinfo, 9569 processor, depth, 9570 merge_b, result_pool, scratch_pool)); 9571 9572 merge_b->notify_begin.nodes_with_mergeinfo = NULL; 9573 9574 return SVN_NO_ERROR; 9575} 9576 9577/** Ensure that *RA_SESSION is opened to URL, either by reusing 9578 * *RA_SESSION if it is non-null and already opened to URL's 9579 * repository, or by allocating a new *RA_SESSION in POOL. 9580 * (RA_SESSION itself cannot be null, of course.) 9581 * 9582 * CTX is used as for svn_client_open_ra_session(). 9583 */ 9584static svn_error_t * 9585ensure_ra_session_url(svn_ra_session_t **ra_session, 9586 const char *url, 9587 const char *wri_abspath, 9588 svn_client_ctx_t *ctx, 9589 apr_pool_t *pool) 9590{ 9591 svn_error_t *err = SVN_NO_ERROR; 9592 9593 if (*ra_session) 9594 { 9595 err = svn_ra_reparent(*ra_session, url, pool); 9596 } 9597 9598 /* SVN_ERR_RA_ILLEGAL_URL is raised when url doesn't point to the same 9599 repository as ra_session. */ 9600 if (! *ra_session || (err && err->apr_err == SVN_ERR_RA_ILLEGAL_URL)) 9601 { 9602 svn_error_clear(err); 9603 err = svn_client_open_ra_session2(ra_session, url, wri_abspath, 9604 ctx, pool, pool); 9605 } 9606 SVN_ERR(err); 9607 9608 return SVN_NO_ERROR; 9609} 9610 9611/* Drive a merge of MERGE_SOURCES into working copy node TARGET 9612 and possibly record mergeinfo describing the merge -- see 9613 RECORD_MERGEINFO(). 9614 9615 If MODIFIED_SUBTREES is not NULL and all the MERGE_SOURCES are 'ancestral' 9616 or REINTEGRATE_MERGE is true, then replace *MODIFIED_SUBTREES with a new 9617 hash containing all the paths that *MODIFIED_SUBTREES contained before, 9618 and also every path modified, skipped, added, or tree-conflicted 9619 by the merge. Keys and values of the hash are both (const char *) 9620 absolute paths. The contents of the hash are allocated in RESULT_POOL. 9621 9622 If the merge raises any conflicts while merging a revision range, return 9623 early and set *CONFLICT_REPORT to describe the details. (In this case, 9624 notify that the merge is complete if and only if this was the last 9625 revision range of the merge.) If there are no conflicts, set 9626 *CONFLICT_REPORT to NULL. A revision range here can be one specified 9627 in MERGE_SOURCES or an internally generated sub-range of one of those 9628 when merge tracking is in use. 9629 9630 For every (const merge_source_t *) merge source in MERGE_SOURCES, if 9631 SOURCE->ANCESTRAL is set, then the "left" and "right" side are 9632 ancestrally related. (See 'MERGEINFO MERGE SOURCE NORMALIZATION' 9633 for more on what that means and how it matters.) 9634 9635 If SOURCES_RELATED is set, the "left" and "right" sides of the 9636 merge source are historically related (ancestors, uncles, second 9637 cousins thrice removed, etc...). (This is passed through to 9638 do_file_merge() to simulate the history checks that the repository 9639 logic does in the directory case.) 9640 9641 SAME_REPOS is TRUE iff the merge sources live in the same 9642 repository as the one from which the target working copy has been 9643 checked out. 9644 9645 If mergeinfo is being recorded, SQUELCH_MERGEINFO_NOTIFICATIONS is FALSE, 9646 and CTX->NOTIFY_FUNC2 is not NULL, then call CTX->NOTIFY_FUNC2 with 9647 CTX->NOTIFY_BATON2 and a svn_wc_notify_merge_record_info_begin 9648 notification before any mergeinfo changes are made to describe the merge 9649 performed. 9650 9651 If mergeinfo is being recorded to describe this merge, and RESULT_CATALOG 9652 is not NULL, then don't record the new mergeinfo on the WC, but instead 9653 record it in RESULT_CATALOG, where the keys are absolute working copy 9654 paths and the values are the new mergeinfos for each. Allocate additions 9655 to RESULT_CATALOG in pool which RESULT_CATALOG was created in. 9656 9657 FORCE_DELETE, DRY_RUN, RECORD_ONLY, DEPTH, MERGE_OPTIONS, 9658 and CTX are as described in the docstring for svn_client_merge_peg3(). 9659 9660 If IGNORE_MERGEINFO is true, disable merge tracking, by treating the two 9661 sources as unrelated even if they actually have a common ancestor. See 9662 the macro HONOR_MERGEINFO(). 9663 9664 If DIFF_IGNORE_ANCESTRY is true, diff the 'left' and 'right' versions 9665 of a node (if they are the same kind) as if they were related, even if 9666 they are not related. Otherwise, diff unrelated items as a deletion 9667 of one thing and the addition of another. 9668 9669 If not NULL, RECORD_ONLY_PATHS is a hash of (const char *) paths mapped 9670 to the same. If RECORD_ONLY is true and RECORD_ONLY_PATHS is not NULL, 9671 then record mergeinfo describing the merge only on subtrees which contain 9672 items from RECORD_ONLY_PATHS. If RECORD_ONLY is true and RECORD_ONLY_PATHS 9673 is NULL, then record mergeinfo on every subtree with mergeinfo in 9674 TARGET. 9675 9676 REINTEGRATE_MERGE is TRUE if this is a reintegrate merge. 9677 9678 *USE_SLEEP will be set TRUE if a sleep is required to ensure timestamp 9679 integrity, *USE_SLEEP will be unchanged if no sleep is required. 9680 9681 SCRATCH_POOL is used for all temporary allocations. 9682*/ 9683static svn_error_t * 9684do_merge(apr_hash_t **modified_subtrees, 9685 svn_mergeinfo_catalog_t result_catalog, 9686 conflict_report_t **conflict_report, 9687 svn_boolean_t *use_sleep, 9688 const apr_array_header_t *merge_sources, 9689 const merge_target_t *target, 9690 svn_ra_session_t *src_session, 9691 svn_boolean_t sources_related, 9692 svn_boolean_t same_repos, 9693 svn_boolean_t ignore_mergeinfo, 9694 svn_boolean_t diff_ignore_ancestry, 9695 svn_boolean_t force_delete, 9696 svn_boolean_t dry_run, 9697 svn_boolean_t record_only, 9698 apr_hash_t *record_only_paths, 9699 svn_boolean_t reintegrate_merge, 9700 svn_boolean_t squelch_mergeinfo_notifications, 9701 svn_depth_t depth, 9702 const apr_array_header_t *merge_options, 9703 svn_client_ctx_t *ctx, 9704 apr_pool_t *result_pool, 9705 apr_pool_t *scratch_pool) 9706{ 9707 merge_cmd_baton_t merge_cmd_baton = { 0 }; 9708 svn_config_t *cfg; 9709 const char *diff3_cmd; 9710 const char *preserved_exts_str; 9711 int i; 9712 svn_boolean_t checked_mergeinfo_capability = FALSE; 9713 svn_ra_session_t *ra_session1 = NULL, *ra_session2 = NULL; 9714 const char *old_src_session_url = NULL; 9715 apr_pool_t *iterpool; 9716 const svn_diff_tree_processor_t *processor; 9717 9718 SVN_ERR_ASSERT(svn_dirent_is_absolute(target->abspath)); 9719 9720 *conflict_report = NULL; 9721 9722 /* Check from some special conditions when in record-only mode 9723 (which is a merge-tracking thing). */ 9724 if (record_only) 9725 { 9726 svn_boolean_t sources_ancestral = TRUE; 9727 int j; 9728 9729 /* Find out whether all of the sources are 'ancestral'. */ 9730 for (j = 0; j < merge_sources->nelts; j++) 9731 if (! APR_ARRAY_IDX(merge_sources, j, merge_source_t *)->ancestral) 9732 { 9733 sources_ancestral = FALSE; 9734 break; 9735 } 9736 9737 /* We can't do a record-only merge if the sources aren't related. */ 9738 if (! sources_ancestral) 9739 return svn_error_create(SVN_ERR_INCORRECT_PARAMS, NULL, 9740 _("Use of two URLs is not compatible with " 9741 "mergeinfo modification")); 9742 9743 /* We can't do a record-only merge if the sources aren't from 9744 the same repository as the target. */ 9745 if (! same_repos) 9746 return svn_error_create(SVN_ERR_INCORRECT_PARAMS, NULL, 9747 _("Merge from foreign repository is not " 9748 "compatible with mergeinfo modification")); 9749 9750 /* If this is a dry-run record-only merge, there's nothing to do. */ 9751 if (dry_run) 9752 return SVN_NO_ERROR; 9753 } 9754 9755 iterpool = svn_pool_create(scratch_pool); 9756 9757 /* Ensure a known depth. */ 9758 if (depth == svn_depth_unknown) 9759 depth = svn_depth_infinity; 9760 9761 /* Set up the diff3 command, so various callers don't have to. */ 9762 cfg = ctx->config 9763 ? svn_hash_gets(ctx->config, SVN_CONFIG_CATEGORY_CONFIG) 9764 : NULL; 9765 svn_config_get(cfg, &diff3_cmd, SVN_CONFIG_SECTION_HELPERS, 9766 SVN_CONFIG_OPTION_DIFF3_CMD, NULL); 9767 9768 if (diff3_cmd != NULL) 9769 SVN_ERR(svn_path_cstring_to_utf8(&diff3_cmd, diff3_cmd, scratch_pool)); 9770 9771 /* See which files the user wants to preserve the extension of when 9772 conflict files are made. */ 9773 svn_config_get(cfg, &preserved_exts_str, SVN_CONFIG_SECTION_MISCELLANY, 9774 SVN_CONFIG_OPTION_PRESERVED_CF_EXTS, ""); 9775 9776 /* Build the merge context baton (or at least the parts of it that 9777 don't need to be reset for each merge source). */ 9778 merge_cmd_baton.force_delete = force_delete; 9779 merge_cmd_baton.dry_run = dry_run; 9780 merge_cmd_baton.record_only = record_only; 9781 merge_cmd_baton.ignore_mergeinfo = ignore_mergeinfo; 9782 merge_cmd_baton.diff_ignore_ancestry = diff_ignore_ancestry; 9783 merge_cmd_baton.same_repos = same_repos; 9784 merge_cmd_baton.mergeinfo_capable = FALSE; 9785 merge_cmd_baton.ctx = ctx; 9786 merge_cmd_baton.reintegrate_merge = reintegrate_merge; 9787 merge_cmd_baton.target = target; 9788 merge_cmd_baton.pool = iterpool; 9789 merge_cmd_baton.merge_options = merge_options; 9790 merge_cmd_baton.diff3_cmd = diff3_cmd; 9791 merge_cmd_baton.ext_patterns = *preserved_exts_str 9792 ? svn_cstring_split(preserved_exts_str, "\n\r\t\v ", 9793 FALSE, scratch_pool) 9794 : NULL; 9795 9796 merge_cmd_baton.use_sleep = use_sleep; 9797 9798 /* Do we already know the specific subtrees with mergeinfo we want 9799 to record-only mergeinfo on? */ 9800 if (record_only && record_only_paths) 9801 merge_cmd_baton.merged_abspaths = record_only_paths; 9802 else 9803 merge_cmd_baton.merged_abspaths = apr_hash_make(result_pool); 9804 9805 merge_cmd_baton.skipped_abspaths = apr_hash_make(result_pool); 9806 merge_cmd_baton.added_abspaths = apr_hash_make(result_pool); 9807 merge_cmd_baton.tree_conflicted_abspaths = apr_hash_make(result_pool); 9808 9809 { 9810 svn_diff_tree_processor_t *merge_processor; 9811 9812 merge_processor = svn_diff__tree_processor_create(&merge_cmd_baton, 9813 scratch_pool); 9814 9815 merge_processor->dir_opened = merge_dir_opened; 9816 merge_processor->dir_changed = merge_dir_changed; 9817 merge_processor->dir_added = merge_dir_added; 9818 merge_processor->dir_deleted = merge_dir_deleted; 9819 merge_processor->dir_closed = merge_dir_closed; 9820 9821 merge_processor->file_opened = merge_file_opened; 9822 merge_processor->file_changed = merge_file_changed; 9823 merge_processor->file_added = merge_file_added; 9824 merge_processor->file_deleted = merge_file_deleted; 9825 /* Not interested in file_closed() */ 9826 9827 merge_processor->node_absent = merge_node_absent; 9828 9829 processor = merge_processor; 9830 } 9831 9832 if (src_session) 9833 { 9834 SVN_ERR(svn_ra_get_session_url(src_session, &old_src_session_url, 9835 scratch_pool)); 9836 ra_session1 = src_session; 9837 } 9838 9839 for (i = 0; i < merge_sources->nelts; i++) 9840 { 9841 svn_node_kind_t src1_kind; 9842 merge_source_t *source = 9843 APR_ARRAY_IDX(merge_sources, i, merge_source_t *); 9844 single_range_conflict_report_t *conflicted_range_report; 9845 9846 svn_pool_clear(iterpool); 9847 9848 /* Sanity check: if our left- and right-side merge sources are 9849 the same, there's nothing to here. */ 9850 if ((strcmp(source->loc1->url, source->loc2->url) == 0) 9851 && (source->loc1->rev == source->loc2->rev)) 9852 continue; 9853 9854 /* Establish RA sessions to our URLs, reuse where possible. */ 9855 SVN_ERR(ensure_ra_session_url(&ra_session1, source->loc1->url, 9856 target->abspath, ctx, scratch_pool)); 9857 SVN_ERR(ensure_ra_session_url(&ra_session2, source->loc2->url, 9858 target->abspath, ctx, scratch_pool)); 9859 9860 /* Populate the portions of the merge context baton that need to 9861 be reset for each merge source iteration. */ 9862 merge_cmd_baton.merge_source = *source; 9863 merge_cmd_baton.implicit_src_gap = NULL; 9864 merge_cmd_baton.conflicted_paths = NULL; 9865 merge_cmd_baton.paths_with_new_mergeinfo = NULL; 9866 merge_cmd_baton.paths_with_deleted_mergeinfo = NULL; 9867 merge_cmd_baton.ra_session1 = ra_session1; 9868 merge_cmd_baton.ra_session2 = ra_session2; 9869 9870 merge_cmd_baton.notify_begin.last_abspath = NULL; 9871 9872 /* Populate the portions of the merge context baton that require 9873 an RA session to set, but shouldn't be reset for each iteration. */ 9874 if (! checked_mergeinfo_capability) 9875 { 9876 SVN_ERR(svn_ra_has_capability(ra_session1, 9877 &merge_cmd_baton.mergeinfo_capable, 9878 SVN_RA_CAPABILITY_MERGEINFO, 9879 iterpool)); 9880 checked_mergeinfo_capability = TRUE; 9881 } 9882 9883 SVN_ERR(svn_ra_check_path(ra_session1, "", source->loc1->rev, 9884 &src1_kind, iterpool)); 9885 9886 /* Run the merge; if there are conflicts, allow the callback to 9887 * resolve them, and if it resolves all of them, then run the 9888 * merge again with the remaining revision range, until it is all 9889 * done. */ 9890 do 9891 { 9892 /* Merge as far as possible without resolving any conflicts */ 9893 if (src1_kind != svn_node_dir) 9894 { 9895 SVN_ERR(do_file_merge(result_catalog, &conflicted_range_report, 9896 source, target->abspath, 9897 processor, 9898 sources_related, 9899 squelch_mergeinfo_notifications, 9900 &merge_cmd_baton, iterpool, iterpool)); 9901 } 9902 else /* Directory */ 9903 { 9904 SVN_ERR(do_directory_merge(result_catalog, &conflicted_range_report, 9905 source, target->abspath, 9906 processor, 9907 depth, squelch_mergeinfo_notifications, 9908 &merge_cmd_baton, iterpool, iterpool)); 9909 } 9910 9911 /* Give the conflict resolver callback the opportunity to 9912 * resolve any conflicts that were raised. If it resolves all 9913 * of them, go around again to merge the next sub-range (if any). */ 9914 if (conflicted_range_report && ctx->conflict_func2 && ! dry_run) 9915 { 9916 svn_boolean_t conflicts_remain; 9917 9918 SVN_ERR(svn_client__resolve_conflicts( 9919 &conflicts_remain, merge_cmd_baton.conflicted_paths, 9920 ctx, iterpool)); 9921 if (conflicts_remain) 9922 break; 9923 9924 merge_cmd_baton.conflicted_paths = NULL; 9925 /* Caution: this source is in iterpool */ 9926 source = conflicted_range_report->remaining_source; 9927 conflicted_range_report = NULL; 9928 } 9929 else 9930 break; 9931 } 9932 while (source); 9933 9934 /* The final mergeinfo on TARGET_WCPATH may itself elide. */ 9935 if (! dry_run) 9936 SVN_ERR(svn_client__elide_mergeinfo(target->abspath, NULL, 9937 ctx, iterpool)); 9938 9939 /* If conflicts occurred while merging any but the very last 9940 * range of a multi-pass merge, we raise an error that aborts 9941 * the merge. The user will be asked to resolve conflicts 9942 * before merging subsequent revision ranges. */ 9943 if (conflicted_range_report) 9944 { 9945 *conflict_report = conflict_report_create( 9946 target->abspath, conflicted_range_report->conflicted_range, 9947 (i == merge_sources->nelts - 1 9948 && ! conflicted_range_report->remaining_source), 9949 result_pool); 9950 break; 9951 } 9952 } 9953 9954 if (! *conflict_report || (*conflict_report)->was_last_range) 9955 { 9956 /* Let everyone know we're finished here. */ 9957 notify_merge_completed(target->abspath, ctx, iterpool); 9958 } 9959 9960 /* Does the caller want to know what the merge has done? */ 9961 if (modified_subtrees) 9962 { 9963 *modified_subtrees = 9964 apr_hash_overlay(result_pool, *modified_subtrees, 9965 merge_cmd_baton.merged_abspaths); 9966 *modified_subtrees = 9967 apr_hash_overlay(result_pool, *modified_subtrees, 9968 merge_cmd_baton.added_abspaths); 9969 *modified_subtrees = 9970 apr_hash_overlay(result_pool, *modified_subtrees, 9971 merge_cmd_baton.skipped_abspaths); 9972 *modified_subtrees = 9973 apr_hash_overlay(result_pool, *modified_subtrees, 9974 merge_cmd_baton.tree_conflicted_abspaths); 9975 } 9976 9977 if (src_session) 9978 SVN_ERR(svn_ra_reparent(src_session, old_src_session_url, iterpool)); 9979 9980 svn_pool_destroy(iterpool); 9981 return SVN_NO_ERROR; 9982} 9983 9984/* Perform a two-URL merge between URLs which are related, but neither 9985 is a direct ancestor of the other. This first does a real two-URL 9986 merge (unless this is record-only), followed by record-only merges 9987 to represent the changed mergeinfo. 9988 9989 Set *CONFLICT_REPORT to indicate if there were any conflicts, as in 9990 do_merge(). 9991 9992 The diff to be merged is between SOURCE->loc1 (in URL1_RA_SESSION1) 9993 and SOURCE->loc2 (in URL2_RA_SESSION2); YCA is their youngest 9994 common ancestor. 9995 9996 SAME_REPOS must be true if and only if the source URLs are in the same 9997 repository as the target working copy. 9998 9999 DIFF_IGNORE_ANCESTRY is as in do_merge(). 10000 10001 Other arguments are as in all of the public merge APIs. 10002 10003 *USE_SLEEP will be set TRUE if a sleep is required to ensure timestamp 10004 integrity, *USE_SLEEP will be unchanged if no sleep is required. 10005 10006 SCRATCH_POOL is used for all temporary allocations. 10007 */ 10008static svn_error_t * 10009merge_cousins_and_supplement_mergeinfo(conflict_report_t **conflict_report, 10010 svn_boolean_t *use_sleep, 10011 const merge_target_t *target, 10012 svn_ra_session_t *URL1_ra_session, 10013 svn_ra_session_t *URL2_ra_session, 10014 const merge_source_t *source, 10015 const svn_client__pathrev_t *yca, 10016 svn_boolean_t same_repos, 10017 svn_depth_t depth, 10018 svn_boolean_t diff_ignore_ancestry, 10019 svn_boolean_t force_delete, 10020 svn_boolean_t record_only, 10021 svn_boolean_t dry_run, 10022 const apr_array_header_t *merge_options, 10023 svn_client_ctx_t *ctx, 10024 apr_pool_t *result_pool, 10025 apr_pool_t *scratch_pool) 10026{ 10027 apr_array_header_t *remove_sources, *add_sources; 10028 apr_hash_t *modified_subtrees = NULL; 10029 10030 /* Sure we could use SCRATCH_POOL throughout this function, but since this 10031 is a wrapper around three separate merges we'll create a subpool we can 10032 clear between each of the three. If the merge target has a lot of 10033 subtree mergeinfo, then this will help keep memory use in check. */ 10034 apr_pool_t *subpool = svn_pool_create(scratch_pool); 10035 10036 assert(session_url_is(URL1_ra_session, source->loc1->url, scratch_pool)); 10037 assert(session_url_is(URL2_ra_session, source->loc2->url, scratch_pool)); 10038 10039 SVN_ERR_ASSERT(svn_dirent_is_absolute(target->abspath)); 10040 SVN_ERR_ASSERT(! source->ancestral); 10041 10042 SVN_ERR(normalize_merge_sources_internal( 10043 &remove_sources, source->loc1, 10044 svn_rangelist__initialize(source->loc1->rev, yca->rev, TRUE, 10045 scratch_pool), 10046 URL1_ra_session, ctx, scratch_pool, subpool)); 10047 10048 SVN_ERR(normalize_merge_sources_internal( 10049 &add_sources, source->loc2, 10050 svn_rangelist__initialize(yca->rev, source->loc2->rev, TRUE, 10051 scratch_pool), 10052 URL2_ra_session, ctx, scratch_pool, subpool)); 10053 10054 *conflict_report = NULL; 10055 10056 /* If this isn't a record-only merge, we'll first do a stupid 10057 point-to-point merge... */ 10058 if (! record_only) 10059 { 10060 apr_array_header_t *faux_sources = 10061 apr_array_make(scratch_pool, 1, sizeof(merge_source_t *)); 10062 10063 modified_subtrees = apr_hash_make(scratch_pool); 10064 APR_ARRAY_PUSH(faux_sources, const merge_source_t *) = source; 10065 SVN_ERR(do_merge(&modified_subtrees, NULL, conflict_report, use_sleep, 10066 faux_sources, target, 10067 URL1_ra_session, TRUE, same_repos, 10068 FALSE /*ignore_mergeinfo*/, diff_ignore_ancestry, 10069 force_delete, dry_run, FALSE, NULL, TRUE, 10070 FALSE, depth, merge_options, ctx, 10071 scratch_pool, subpool)); 10072 if (*conflict_report) 10073 { 10074 *conflict_report = conflict_report_dup(*conflict_report, result_pool); 10075 if (! (*conflict_report)->was_last_range) 10076 return SVN_NO_ERROR; 10077 } 10078 } 10079 else if (! same_repos) 10080 { 10081 return svn_error_create(SVN_ERR_INCORRECT_PARAMS, NULL, 10082 _("Merge from foreign repository is not " 10083 "compatible with mergeinfo modification")); 10084 } 10085 10086 /* ... and now, if we're doing the mergeinfo thang, we execute a 10087 pair of record-only merges using the real sources we've 10088 calculated. 10089 10090 Issue #3648: We don't actually perform these two record-only merges 10091 on the WC at first, but rather see what each would do and store that 10092 in two mergeinfo catalogs. We then merge the catalogs together and 10093 then record the result in the WC. This prevents the second record 10094 only merge from removing legitimate mergeinfo history, from the same 10095 source, that was made in prior merges. */ 10096 if (same_repos && !dry_run) 10097 { 10098 svn_mergeinfo_catalog_t add_result_catalog = 10099 apr_hash_make(scratch_pool); 10100 svn_mergeinfo_catalog_t remove_result_catalog = 10101 apr_hash_make(scratch_pool); 10102 10103 notify_mergeinfo_recording(target->abspath, NULL, ctx, scratch_pool); 10104 svn_pool_clear(subpool); 10105 SVN_ERR(do_merge(NULL, add_result_catalog, conflict_report, use_sleep, 10106 add_sources, target, 10107 URL1_ra_session, TRUE, same_repos, 10108 FALSE /*ignore_mergeinfo*/, diff_ignore_ancestry, 10109 force_delete, dry_run, TRUE, 10110 modified_subtrees, TRUE, 10111 TRUE, depth, merge_options, ctx, 10112 scratch_pool, subpool)); 10113 if (*conflict_report) 10114 { 10115 *conflict_report = conflict_report_dup(*conflict_report, result_pool); 10116 if (! (*conflict_report)->was_last_range) 10117 return SVN_NO_ERROR; 10118 } 10119 svn_pool_clear(subpool); 10120 SVN_ERR(do_merge(NULL, remove_result_catalog, conflict_report, use_sleep, 10121 remove_sources, target, 10122 URL1_ra_session, TRUE, same_repos, 10123 FALSE /*ignore_mergeinfo*/, diff_ignore_ancestry, 10124 force_delete, dry_run, TRUE, 10125 modified_subtrees, TRUE, 10126 TRUE, depth, merge_options, ctx, 10127 scratch_pool, subpool)); 10128 if (*conflict_report) 10129 { 10130 *conflict_report = conflict_report_dup(*conflict_report, result_pool); 10131 if (! (*conflict_report)->was_last_range) 10132 return SVN_NO_ERROR; 10133 } 10134 SVN_ERR(svn_mergeinfo_catalog_merge(add_result_catalog, 10135 remove_result_catalog, 10136 scratch_pool, scratch_pool)); 10137 SVN_ERR(svn_client__record_wc_mergeinfo_catalog(add_result_catalog, 10138 ctx, scratch_pool)); 10139 } 10140 10141 svn_pool_destroy(subpool); 10142 return SVN_NO_ERROR; 10143} 10144 10145/* Perform checks to determine whether the working copy at TARGET_ABSPATH 10146 * can safely be used as a merge target. Checks are performed according to 10147 * the ALLOW_MIXED_REV, ALLOW_LOCAL_MODS, and ALLOW_SWITCHED_SUBTREES 10148 * parameters. If any checks fail, raise SVN_ERR_CLIENT_NOT_READY_TO_MERGE. 10149 * 10150 * E.g. if all the ALLOW_* parameters are FALSE, TARGET_ABSPATH must 10151 * be a single-revision, pristine, unswitched working copy. 10152 * In other words, it must reflect a subtree of the repository as found 10153 * at single revision -- although sparse checkouts are permitted. */ 10154static svn_error_t * 10155ensure_wc_is_suitable_merge_target(const char *target_abspath, 10156 svn_client_ctx_t *ctx, 10157 svn_boolean_t allow_mixed_rev, 10158 svn_boolean_t allow_local_mods, 10159 svn_boolean_t allow_switched_subtrees, 10160 apr_pool_t *scratch_pool) 10161{ 10162 svn_node_kind_t target_kind; 10163 10164 /* Check the target exists. */ 10165 SVN_ERR(svn_io_check_path(target_abspath, &target_kind, scratch_pool)); 10166 if (target_kind == svn_node_none) 10167 return svn_error_createf(SVN_ERR_WC_PATH_NOT_FOUND, NULL, 10168 _("Path '%s' does not exist"), 10169 svn_dirent_local_style(target_abspath, 10170 scratch_pool)); 10171 SVN_ERR(svn_wc_read_kind2(&target_kind, ctx->wc_ctx, target_abspath, 10172 FALSE, FALSE, scratch_pool)); 10173 if (target_kind != svn_node_dir && target_kind != svn_node_file) 10174 return svn_error_createf(SVN_ERR_ILLEGAL_TARGET, NULL, 10175 _("Merge target '%s' does not exist in the " 10176 "working copy"), target_abspath); 10177 10178 /* Perform the mixed-revision check first because it's the cheapest one. */ 10179 if (! allow_mixed_rev) 10180 { 10181 svn_revnum_t min_rev; 10182 svn_revnum_t max_rev; 10183 10184 SVN_ERR(svn_client_min_max_revisions(&min_rev, &max_rev, target_abspath, 10185 FALSE, ctx, scratch_pool)); 10186 10187 if (!(SVN_IS_VALID_REVNUM(min_rev) && SVN_IS_VALID_REVNUM(max_rev))) 10188 { 10189 svn_boolean_t is_added; 10190 10191 /* Allow merge into added nodes. */ 10192 SVN_ERR(svn_wc__node_is_added(&is_added, ctx->wc_ctx, target_abspath, 10193 scratch_pool)); 10194 if (is_added) 10195 return SVN_NO_ERROR; 10196 else 10197 return svn_error_create(SVN_ERR_CLIENT_NOT_READY_TO_MERGE, NULL, 10198 _("Cannot determine revision of working " 10199 "copy")); 10200 } 10201 10202 if (min_rev != max_rev) 10203 return svn_error_createf(SVN_ERR_CLIENT_MERGE_UPDATE_REQUIRED, NULL, 10204 _("Cannot merge into mixed-revision working " 10205 "copy [%ld:%ld]; try updating first"), 10206 min_rev, max_rev); 10207 } 10208 10209 /* Next, check for switched subtrees. */ 10210 if (! allow_switched_subtrees) 10211 { 10212 svn_boolean_t is_switched; 10213 10214 SVN_ERR(svn_wc__has_switched_subtrees(&is_switched, ctx->wc_ctx, 10215 target_abspath, NULL, 10216 scratch_pool)); 10217 if (is_switched) 10218 return svn_error_create(SVN_ERR_CLIENT_NOT_READY_TO_MERGE, NULL, 10219 _("Cannot merge into a working copy " 10220 "with a switched subtree")); 10221 } 10222 10223 /* This is the most expensive check, so it is performed last.*/ 10224 if (! allow_local_mods) 10225 { 10226 svn_boolean_t is_modified; 10227 10228 SVN_ERR(svn_wc__has_local_mods(&is_modified, ctx->wc_ctx, 10229 target_abspath, 10230 ctx->cancel_func, 10231 ctx->cancel_baton, 10232 scratch_pool)); 10233 if (is_modified) 10234 return svn_error_create(SVN_ERR_CLIENT_NOT_READY_TO_MERGE, NULL, 10235 _("Cannot merge into a working copy " 10236 "that has local modifications")); 10237 } 10238 10239 return SVN_NO_ERROR; 10240} 10241 10242/* Throw an error if PATH_OR_URL is a path and REVISION isn't a repository 10243 * revision. */ 10244static svn_error_t * 10245ensure_wc_path_has_repo_revision(const char *path_or_url, 10246 const svn_opt_revision_t *revision, 10247 apr_pool_t *scratch_pool) 10248{ 10249 if (revision->kind != svn_opt_revision_number 10250 && revision->kind != svn_opt_revision_date 10251 && revision->kind != svn_opt_revision_head 10252 && ! svn_path_is_url(path_or_url)) 10253 return svn_error_createf( 10254 SVN_ERR_CLIENT_BAD_REVISION, NULL, 10255 _("Invalid merge source '%s'; a working copy path can only be " 10256 "used with a repository revision (a number, a date, or head)"), 10257 svn_dirent_local_style(path_or_url, scratch_pool)); 10258 return SVN_NO_ERROR; 10259} 10260 10261/* "Open" the target WC for a merge. That means: 10262 * - find out its exact repository location 10263 * - check the WC for suitability (throw an error if unsuitable) 10264 * 10265 * Set *TARGET_P to a new, fully initialized, target description structure. 10266 * 10267 * ALLOW_MIXED_REV, ALLOW_LOCAL_MODS, ALLOW_SWITCHED_SUBTREES determine 10268 * whether the WC is deemed suitable; see ensure_wc_is_suitable_merge_target() 10269 * for details. 10270 * 10271 * If the node is locally added, the rev and URL will be null/invalid. Some 10272 * kinds of merge can use such a target; others can't. 10273 */ 10274static svn_error_t * 10275open_target_wc(merge_target_t **target_p, 10276 const char *wc_abspath, 10277 svn_boolean_t allow_mixed_rev, 10278 svn_boolean_t allow_local_mods, 10279 svn_boolean_t allow_switched_subtrees, 10280 svn_client_ctx_t *ctx, 10281 apr_pool_t *result_pool, 10282 apr_pool_t *scratch_pool) 10283{ 10284 merge_target_t *target = apr_palloc(result_pool, sizeof(*target)); 10285 svn_client__pathrev_t *origin; 10286 10287 target->abspath = apr_pstrdup(result_pool, wc_abspath); 10288 10289 SVN_ERR(svn_client__wc_node_get_origin(&origin, wc_abspath, ctx, 10290 result_pool, scratch_pool)); 10291 if (origin) 10292 { 10293 target->loc = *origin; 10294 } 10295 else 10296 { 10297 svn_error_t *err; 10298 /* The node has no location in the repository. It's unversioned or 10299 * locally added or locally deleted. 10300 * 10301 * If it's locally added or deleted, find the repository root 10302 * URL and UUID anyway, and leave the node URL and revision as NULL 10303 * and INVALID. If it's unversioned, this will throw an error. */ 10304 err = svn_wc__node_get_repos_info(NULL, NULL, 10305 &target->loc.repos_root_url, 10306 &target->loc.repos_uuid, 10307 ctx->wc_ctx, wc_abspath, 10308 result_pool, scratch_pool); 10309 10310 if (err) 10311 { 10312 if (err->apr_err != SVN_ERR_WC_PATH_NOT_FOUND 10313 && err->apr_err != SVN_ERR_WC_NOT_WORKING_COPY 10314 && err->apr_err != SVN_ERR_WC_UPGRADE_REQUIRED) 10315 return svn_error_trace(err); 10316 10317 return svn_error_createf(SVN_ERR_ILLEGAL_TARGET, err, 10318 _("Merge target '%s' does not exist in the " 10319 "working copy"), 10320 svn_dirent_local_style(wc_abspath, 10321 scratch_pool)); 10322 } 10323 10324 target->loc.rev = SVN_INVALID_REVNUM; 10325 target->loc.url = NULL; 10326 } 10327 10328 SVN_ERR(ensure_wc_is_suitable_merge_target( 10329 wc_abspath, ctx, 10330 allow_mixed_rev, allow_local_mods, allow_switched_subtrees, 10331 scratch_pool)); 10332 10333 *target_p = target; 10334 return SVN_NO_ERROR; 10335} 10336 10337/*-----------------------------------------------------------------------*/ 10338 10339/*** Public APIs ***/ 10340 10341/* The body of svn_client_merge5(), which see for details. 10342 * 10343 * If SOURCE1 @ REVISION1 is related to SOURCE2 @ REVISION2 then use merge 10344 * tracking (subject to other constraints -- see HONOR_MERGEINFO()); 10345 * otherwise disable merge tracking. 10346 * 10347 * IGNORE_MERGEINFO and DIFF_IGNORE_ANCESTRY are as in do_merge(). 10348 */ 10349static svn_error_t * 10350merge_locked(conflict_report_t **conflict_report, 10351 const char *source1, 10352 const svn_opt_revision_t *revision1, 10353 const char *source2, 10354 const svn_opt_revision_t *revision2, 10355 const char *target_abspath, 10356 svn_depth_t depth, 10357 svn_boolean_t ignore_mergeinfo, 10358 svn_boolean_t diff_ignore_ancestry, 10359 svn_boolean_t force_delete, 10360 svn_boolean_t record_only, 10361 svn_boolean_t dry_run, 10362 svn_boolean_t allow_mixed_rev, 10363 const apr_array_header_t *merge_options, 10364 svn_client_ctx_t *ctx, 10365 apr_pool_t *result_pool, 10366 apr_pool_t *scratch_pool) 10367{ 10368 merge_target_t *target; 10369 svn_client__pathrev_t *source1_loc, *source2_loc; 10370 svn_boolean_t sources_related = FALSE; 10371 svn_ra_session_t *ra_session1, *ra_session2; 10372 apr_array_header_t *merge_sources; 10373 svn_error_t *err; 10374 svn_boolean_t use_sleep = FALSE; 10375 svn_client__pathrev_t *yca = NULL; 10376 apr_pool_t *sesspool; 10377 svn_boolean_t same_repos; 10378 10379 /* ### FIXME: This function really ought to do a history check on 10380 the left and right sides of the merge source, and -- if one is an 10381 ancestor of the other -- just call svn_client_merge_peg3() with 10382 the appropriate args. */ 10383 10384 SVN_ERR(open_target_wc(&target, target_abspath, 10385 allow_mixed_rev, TRUE, TRUE, 10386 ctx, scratch_pool, scratch_pool)); 10387 10388 /* Open RA sessions to both sides of our merge source, and resolve URLs 10389 * and revisions. */ 10390 sesspool = svn_pool_create(scratch_pool); 10391 SVN_ERR(svn_client__ra_session_from_path2( 10392 &ra_session1, &source1_loc, 10393 source1, NULL, revision1, revision1, ctx, sesspool)); 10394 SVN_ERR(svn_client__ra_session_from_path2( 10395 &ra_session2, &source2_loc, 10396 source2, NULL, revision2, revision2, ctx, sesspool)); 10397 10398 /* We can't do a diff between different repositories. */ 10399 /* ### We should also insist that the root URLs of the two sources match, 10400 * as we are only carrying around a single source-repos-root from now 10401 * on, and URL calculations will go wrong if they differ. 10402 * Alternatively, teach the code to cope with differing root URLs. */ 10403 SVN_ERR(check_same_repos(source1_loc, source1_loc->url, 10404 source2_loc, source2_loc->url, 10405 FALSE /* strict_urls */, scratch_pool)); 10406 10407 /* Do our working copy and sources come from the same repository? */ 10408 same_repos = is_same_repos(&target->loc, source1_loc, TRUE /* strict_urls */); 10409 10410 /* Unless we're ignoring ancestry, see if the two sources are related. */ 10411 if (! ignore_mergeinfo) 10412 SVN_ERR(svn_client__get_youngest_common_ancestor( 10413 &yca, source1_loc, source2_loc, ra_session1, ctx, 10414 scratch_pool, scratch_pool)); 10415 10416 /* Check for a youngest common ancestor. If we have one, we'll be 10417 doing merge tracking. 10418 10419 So, given a requested merge of the differences between A and 10420 B, and a common ancestor of C, we will find ourselves in one of 10421 four positions, and four different approaches: 10422 10423 A == B == C there's nothing to merge 10424 10425 A == C != B we merge the changes between A (or C) and B 10426 10427 B == C != A we merge the changes between B (or C) and A 10428 10429 A != B != C we merge the changes between A and B without 10430 merge recording, then record-only two merges: 10431 from A to C, and from C to B 10432 */ 10433 if (yca) 10434 { 10435 /* Note that our merge sources are related. */ 10436 sources_related = TRUE; 10437 10438 /* If the common ancestor matches the right side of our merge, 10439 then we only need to reverse-merge the left side. */ 10440 if ((strcmp(yca->url, source2_loc->url) == 0) 10441 && (yca->rev == source2_loc->rev)) 10442 { 10443 SVN_ERR(normalize_merge_sources_internal( 10444 &merge_sources, source1_loc, 10445 svn_rangelist__initialize(source1_loc->rev, yca->rev, TRUE, 10446 scratch_pool), 10447 ra_session1, ctx, scratch_pool, scratch_pool)); 10448 } 10449 /* If the common ancestor matches the left side of our merge, 10450 then we only need to merge the right side. */ 10451 else if ((strcmp(yca->url, source1_loc->url) == 0) 10452 && (yca->rev == source1_loc->rev)) 10453 { 10454 SVN_ERR(normalize_merge_sources_internal( 10455 &merge_sources, source2_loc, 10456 svn_rangelist__initialize(yca->rev, source2_loc->rev, TRUE, 10457 scratch_pool), 10458 ra_session2, ctx, scratch_pool, scratch_pool)); 10459 } 10460 /* And otherwise, we need to do both: reverse merge the left 10461 side, and merge the right. */ 10462 else 10463 { 10464 merge_source_t source; 10465 10466 source.loc1 = source1_loc; 10467 source.loc2 = source2_loc; 10468 source.ancestral = FALSE; 10469 10470 err = merge_cousins_and_supplement_mergeinfo(conflict_report, 10471 &use_sleep, 10472 target, 10473 ra_session1, 10474 ra_session2, 10475 &source, 10476 yca, 10477 same_repos, 10478 depth, 10479 diff_ignore_ancestry, 10480 force_delete, 10481 record_only, dry_run, 10482 merge_options, 10483 ctx, 10484 result_pool, 10485 scratch_pool); 10486 /* Close our temporary RA sessions (this could've happened 10487 after the second call to normalize_merge_sources() inside 10488 the merge_cousins_and_supplement_mergeinfo() routine). */ 10489 svn_pool_destroy(sesspool); 10490 10491 if (use_sleep) 10492 svn_io_sleep_for_timestamps(target->abspath, scratch_pool); 10493 10494 SVN_ERR(err); 10495 return SVN_NO_ERROR; 10496 } 10497 } 10498 else 10499 { 10500 /* Build a single-item merge_source_t array. */ 10501 merge_sources = apr_array_make(scratch_pool, 1, sizeof(merge_source_t *)); 10502 APR_ARRAY_PUSH(merge_sources, merge_source_t *) 10503 = merge_source_create(source1_loc, source2_loc, FALSE, scratch_pool); 10504 } 10505 10506 err = do_merge(NULL, NULL, conflict_report, &use_sleep, 10507 merge_sources, target, 10508 ra_session1, sources_related, same_repos, 10509 ignore_mergeinfo, diff_ignore_ancestry, force_delete, dry_run, 10510 record_only, NULL, FALSE, FALSE, depth, merge_options, 10511 ctx, result_pool, scratch_pool); 10512 10513 /* Close our temporary RA sessions. */ 10514 svn_pool_destroy(sesspool); 10515 10516 if (use_sleep) 10517 svn_io_sleep_for_timestamps(target->abspath, scratch_pool); 10518 10519 SVN_ERR(err); 10520 return SVN_NO_ERROR; 10521} 10522 10523/* Set *TARGET_ABSPATH to the absolute path of, and *LOCK_ABSPATH to 10524 the absolute path to lock for, TARGET_WCPATH. */ 10525static svn_error_t * 10526get_target_and_lock_abspath(const char **target_abspath, 10527 const char **lock_abspath, 10528 const char *target_wcpath, 10529 svn_client_ctx_t *ctx, 10530 apr_pool_t *result_pool) 10531{ 10532 svn_node_kind_t kind; 10533 SVN_ERR(svn_dirent_get_absolute(target_abspath, target_wcpath, 10534 result_pool)); 10535 SVN_ERR(svn_wc_read_kind2(&kind, ctx->wc_ctx, *target_abspath, 10536 FALSE, FALSE, result_pool)); 10537 if (kind == svn_node_dir) 10538 *lock_abspath = *target_abspath; 10539 else 10540 *lock_abspath = svn_dirent_dirname(*target_abspath, result_pool); 10541 10542 return SVN_NO_ERROR; 10543} 10544 10545svn_error_t * 10546svn_client_merge5(const char *source1, 10547 const svn_opt_revision_t *revision1, 10548 const char *source2, 10549 const svn_opt_revision_t *revision2, 10550 const char *target_wcpath, 10551 svn_depth_t depth, 10552 svn_boolean_t ignore_mergeinfo, 10553 svn_boolean_t diff_ignore_ancestry, 10554 svn_boolean_t force_delete, 10555 svn_boolean_t record_only, 10556 svn_boolean_t dry_run, 10557 svn_boolean_t allow_mixed_rev, 10558 const apr_array_header_t *merge_options, 10559 svn_client_ctx_t *ctx, 10560 apr_pool_t *pool) 10561{ 10562 const char *target_abspath, *lock_abspath; 10563 conflict_report_t *conflict_report; 10564 10565 /* Sanity check our input -- we require specified revisions, 10566 * and either 2 paths or 2 URLs. */ 10567 if ((revision1->kind == svn_opt_revision_unspecified) 10568 || (revision2->kind == svn_opt_revision_unspecified)) 10569 return svn_error_create(SVN_ERR_CLIENT_BAD_REVISION, NULL, 10570 _("Not all required revisions are specified")); 10571 if (svn_path_is_url(source1) != svn_path_is_url(source2)) 10572 return svn_error_create(SVN_ERR_ILLEGAL_TARGET, NULL, 10573 _("Merge sources must both be " 10574 "either paths or URLs")); 10575 /* A WC path must be used with a repository revision, as we can't 10576 * (currently) use the WC itself as a source, we can only read the URL 10577 * from it and use that. */ 10578 SVN_ERR(ensure_wc_path_has_repo_revision(source1, revision1, pool)); 10579 SVN_ERR(ensure_wc_path_has_repo_revision(source2, revision2, pool)); 10580 10581 SVN_ERR(get_target_and_lock_abspath(&target_abspath, &lock_abspath, 10582 target_wcpath, ctx, pool)); 10583 10584 if (!dry_run) 10585 SVN_WC__CALL_WITH_WRITE_LOCK( 10586 merge_locked(&conflict_report, 10587 source1, revision1, source2, revision2, 10588 target_abspath, depth, ignore_mergeinfo, 10589 diff_ignore_ancestry, 10590 force_delete, record_only, dry_run, 10591 allow_mixed_rev, merge_options, ctx, pool, pool), 10592 ctx->wc_ctx, lock_abspath, FALSE /* lock_anchor */, pool); 10593 else 10594 SVN_ERR(merge_locked(&conflict_report, 10595 source1, revision1, source2, revision2, 10596 target_abspath, depth, ignore_mergeinfo, 10597 diff_ignore_ancestry, 10598 force_delete, record_only, dry_run, 10599 allow_mixed_rev, merge_options, ctx, pool, pool)); 10600 10601 SVN_ERR(make_merge_conflict_error(conflict_report, pool)); 10602 return SVN_NO_ERROR; 10603} 10604 10605 10606/* Check if mergeinfo for a given path is described explicitly or via 10607 inheritance in a mergeinfo catalog. 10608 10609 If REPOS_REL_PATH exists in CATALOG and has mergeinfo containing 10610 MERGEINFO, then set *IN_CATALOG to TRUE. If REPOS_REL_PATH does 10611 not exist in CATALOG, then find its nearest parent which does exist. 10612 If the mergeinfo REPOS_REL_PATH would inherit from that parent 10613 contains MERGEINFO then set *IN_CATALOG to TRUE. Set *IN_CATALOG 10614 to FALSE in all other cases. 10615 10616 Set *CAT_KEY_PATH to the key path in CATALOG for REPOS_REL_PATH's 10617 explicit or inherited mergeinfo. If no explicit or inherited mergeinfo 10618 is found for REPOS_REL_PATH then set *CAT_KEY_PATH to NULL. 10619 10620 User RESULT_POOL to allocate *CAT_KEY_PATH. Use SCRATCH_POOL for 10621 temporary allocations. */ 10622static svn_error_t * 10623mergeinfo_in_catalog(svn_boolean_t *in_catalog, 10624 const char **cat_key_path, 10625 const char *repos_rel_path, 10626 svn_mergeinfo_t mergeinfo, 10627 svn_mergeinfo_catalog_t catalog, 10628 apr_pool_t *result_pool, 10629 apr_pool_t *scratch_pool) 10630{ 10631 const char *walk_path = NULL; 10632 10633 *in_catalog = FALSE; 10634 *cat_key_path = NULL; 10635 10636 if (mergeinfo && catalog && apr_hash_count(catalog)) 10637 { 10638 const char *path = repos_rel_path; 10639 10640 /* Start with the assumption there is no explicit or inherited 10641 mergeinfo for REPOS_REL_PATH in CATALOG. */ 10642 svn_mergeinfo_t mergeinfo_in_cat = NULL; 10643 10644 while (1) 10645 { 10646 mergeinfo_in_cat = svn_hash_gets(catalog, path); 10647 10648 if (mergeinfo_in_cat) /* Found it! */ 10649 { 10650 *cat_key_path = apr_pstrdup(result_pool, path); 10651 break; 10652 } 10653 else /* Look for inherited mergeinfo. */ 10654 { 10655 walk_path = svn_relpath_join(svn_relpath_basename(path, 10656 scratch_pool), 10657 walk_path ? walk_path : "", 10658 scratch_pool); 10659 path = svn_relpath_dirname(path, scratch_pool); 10660 10661 if (path[0] == '\0') /* No mergeinfo to inherit. */ 10662 break; 10663 } 10664 } 10665 10666 if (mergeinfo_in_cat) 10667 { 10668 if (walk_path) 10669 SVN_ERR(svn_mergeinfo__add_suffix_to_mergeinfo(&mergeinfo_in_cat, 10670 mergeinfo_in_cat, 10671 walk_path, 10672 scratch_pool, 10673 scratch_pool)); 10674 SVN_ERR(svn_mergeinfo_intersect2(&mergeinfo_in_cat, 10675 mergeinfo_in_cat, mergeinfo, 10676 TRUE, 10677 scratch_pool, scratch_pool)); 10678 SVN_ERR(svn_mergeinfo__equals(in_catalog, mergeinfo_in_cat, 10679 mergeinfo, TRUE, scratch_pool)); 10680 } 10681 } 10682 10683 return SVN_NO_ERROR; 10684} 10685 10686/* A svn_log_entry_receiver_t baton for log_find_operative_revs(). */ 10687typedef struct log_find_operative_baton_t 10688{ 10689 /* The catalog of explicit mergeinfo on a reintegrate source. */ 10690 svn_mergeinfo_catalog_t merged_catalog; 10691 10692 /* The catalog of unmerged history from the reintegrate target to 10693 the source which we will create. Allocated in RESULT_POOL. */ 10694 svn_mergeinfo_catalog_t unmerged_catalog; 10695 10696 /* The repository absolute path of the reintegrate target. */ 10697 const char *target_fspath; 10698 10699 /* The path of the reintegrate source relative to the repository root. */ 10700 const char *source_repos_rel_path; 10701 10702 apr_pool_t *result_pool; 10703} log_find_operative_baton_t; 10704 10705/* A svn_log_entry_receiver_t callback for find_unsynced_ranges(). */ 10706static svn_error_t * 10707log_find_operative_revs(void *baton, 10708 svn_log_entry_t *log_entry, 10709 apr_pool_t *pool) 10710{ 10711 log_find_operative_baton_t *log_baton = baton; 10712 apr_hash_index_t *hi; 10713 svn_revnum_t revision; 10714 10715 /* It's possible that authz restrictions on the merge source prevent us 10716 from knowing about any of the changes for LOG_ENTRY->REVISION. */ 10717 if (!log_entry->changed_paths2) 10718 return SVN_NO_ERROR; 10719 10720 revision = log_entry->revision; 10721 10722 for (hi = apr_hash_first(pool, log_entry->changed_paths2); 10723 hi; 10724 hi = apr_hash_next(hi)) 10725 { 10726 const char *subtree_missing_this_rev; 10727 const char *path = svn__apr_hash_index_key(hi); 10728 const char *rel_path; 10729 const char *source_rel_path; 10730 svn_boolean_t in_catalog; 10731 svn_mergeinfo_t log_entry_as_mergeinfo; 10732 10733 rel_path = svn_fspath__skip_ancestor(log_baton->target_fspath, path); 10734 /* Easy out: The path is not within the tree of interest. */ 10735 if (rel_path == NULL) 10736 continue; 10737 10738 source_rel_path = svn_relpath_join(log_baton->source_repos_rel_path, 10739 rel_path, pool); 10740 10741 SVN_ERR(svn_mergeinfo_parse(&log_entry_as_mergeinfo, 10742 apr_psprintf(pool, "%s:%ld", 10743 path, revision), 10744 pool)); 10745 10746 SVN_ERR(mergeinfo_in_catalog(&in_catalog, &subtree_missing_this_rev, 10747 source_rel_path, log_entry_as_mergeinfo, 10748 log_baton->merged_catalog, 10749 pool, pool)); 10750 10751 if (!in_catalog) 10752 { 10753 svn_mergeinfo_t unmerged_for_key; 10754 const char *suffix, *missing_path; 10755 10756 /* If there is no mergeinfo on the source tree we'll say 10757 the "subtree" missing this revision is the root of the 10758 source. */ 10759 if (!subtree_missing_this_rev) 10760 subtree_missing_this_rev = log_baton->source_repos_rel_path; 10761 10762 suffix = svn_relpath_skip_ancestor(subtree_missing_this_rev, 10763 source_rel_path); 10764 if (suffix && suffix[0] != '\0') 10765 { 10766 missing_path = apr_pstrmemdup(pool, path, 10767 strlen(path) - strlen(suffix) - 1); 10768 } 10769 else 10770 { 10771 missing_path = path; 10772 } 10773 10774 SVN_ERR(svn_mergeinfo_parse(&log_entry_as_mergeinfo, 10775 apr_psprintf(pool, "%s:%ld", 10776 missing_path, revision), 10777 log_baton->result_pool)); 10778 unmerged_for_key = svn_hash_gets(log_baton->unmerged_catalog, 10779 subtree_missing_this_rev); 10780 10781 if (unmerged_for_key) 10782 { 10783 SVN_ERR(svn_mergeinfo_merge2(unmerged_for_key, 10784 log_entry_as_mergeinfo, 10785 log_baton->result_pool, 10786 pool)); 10787 } 10788 else 10789 { 10790 svn_hash_sets(log_baton->unmerged_catalog, 10791 apr_pstrdup(log_baton->result_pool, 10792 subtree_missing_this_rev), 10793 log_entry_as_mergeinfo); 10794 } 10795 10796 } 10797 } 10798 return SVN_NO_ERROR; 10799} 10800 10801/* Determine if the mergeinfo on a reintegrate source SOURCE_LOC, 10802 reflects that the source is fully synced with the reintegrate target 10803 TARGET_LOC, even if a naive interpretation of the source's 10804 mergeinfo says otherwise -- See issue #3577. 10805 10806 UNMERGED_CATALOG represents the history (as mergeinfo) from 10807 TARGET_LOC that is not represented in SOURCE_LOC's 10808 explicit/inherited mergeinfo as represented by MERGED_CATALOG. 10809 MERGED_CATALOG may be empty if the source has no explicit or inherited 10810 mergeinfo. 10811 10812 Check that all of the unmerged revisions in UNMERGED_CATALOG's 10813 mergeinfos are "phantoms", that is, one of the following conditions holds: 10814 10815 1) The revision affects no corresponding paths in SOURCE_LOC. 10816 10817 2) The revision affects corresponding paths in SOURCE_LOC, 10818 but based on the mergeinfo in MERGED_CATALOG, the change was 10819 previously merged. 10820 10821 Make a deep copy, allocated in RESULT_POOL, of any portions of 10822 UNMERGED_CATALOG that are not phantoms, to TRUE_UNMERGED_CATALOG. 10823 10824 Note: The keys in all mergeinfo catalogs used here are relative to the 10825 root of the repository. 10826 10827 RA_SESSION is an RA session open to the repository of TARGET_LOC; it may 10828 be temporarily reparented within this function. 10829 10830 Use SCRATCH_POOL for all temporary allocations. */ 10831static svn_error_t * 10832find_unsynced_ranges(const svn_client__pathrev_t *source_loc, 10833 const svn_client__pathrev_t *target_loc, 10834 svn_mergeinfo_catalog_t unmerged_catalog, 10835 svn_mergeinfo_catalog_t merged_catalog, 10836 svn_mergeinfo_catalog_t true_unmerged_catalog, 10837 svn_ra_session_t *ra_session, 10838 apr_pool_t *result_pool, 10839 apr_pool_t *scratch_pool) 10840{ 10841 svn_rangelist_t *potentially_unmerged_ranges = NULL; 10842 10843 /* Convert all the unmerged history to a rangelist. */ 10844 if (apr_hash_count(unmerged_catalog)) 10845 { 10846 apr_hash_index_t *hi_catalog; 10847 10848 potentially_unmerged_ranges = 10849 apr_array_make(scratch_pool, 1, sizeof(svn_merge_range_t *)); 10850 10851 for (hi_catalog = apr_hash_first(scratch_pool, unmerged_catalog); 10852 hi_catalog; 10853 hi_catalog = apr_hash_next(hi_catalog)) 10854 { 10855 svn_mergeinfo_t mergeinfo = svn__apr_hash_index_val(hi_catalog); 10856 10857 SVN_ERR(svn_rangelist__merge_many(potentially_unmerged_ranges, 10858 mergeinfo, 10859 scratch_pool, scratch_pool)); 10860 } 10861 } 10862 10863 /* Find any unmerged revisions which both affect the source and 10864 are not yet merged to it. */ 10865 if (potentially_unmerged_ranges) 10866 { 10867 svn_revnum_t oldest_rev = 10868 (APR_ARRAY_IDX(potentially_unmerged_ranges, 10869 0, 10870 svn_merge_range_t *))->start + 1; 10871 svn_revnum_t youngest_rev = 10872 (APR_ARRAY_IDX(potentially_unmerged_ranges, 10873 potentially_unmerged_ranges->nelts - 1, 10874 svn_merge_range_t *))->end; 10875 log_find_operative_baton_t log_baton; 10876 const char *old_session_url; 10877 svn_error_t *err; 10878 10879 log_baton.merged_catalog = merged_catalog; 10880 log_baton.unmerged_catalog = true_unmerged_catalog; 10881 log_baton.source_repos_rel_path 10882 = svn_client__pathrev_relpath(source_loc, scratch_pool); 10883 log_baton.target_fspath 10884 = svn_client__pathrev_fspath(target_loc, scratch_pool); 10885 log_baton.result_pool = result_pool; 10886 10887 SVN_ERR(svn_client__ensure_ra_session_url( 10888 &old_session_url, ra_session, target_loc->url, scratch_pool)); 10889 err = get_log(ra_session, "", youngest_rev, oldest_rev, 10890 TRUE, /* discover_changed_paths */ 10891 log_find_operative_revs, &log_baton, 10892 scratch_pool); 10893 SVN_ERR(svn_error_compose_create( 10894 err, svn_ra_reparent(ra_session, old_session_url, scratch_pool))); 10895 } 10896 10897 return SVN_NO_ERROR; 10898} 10899 10900 10901/* Find the youngest revision that has been merged from target to source. 10902 * 10903 * If any location in TARGET_HISTORY_AS_MERGEINFO is mentioned in 10904 * SOURCE_MERGEINFO, then we know that at least one merge was done from the 10905 * target to the source. In that case, set *YOUNGEST_MERGED_REV to the 10906 * youngest revision of that intersection (unless *YOUNGEST_MERGED_REV is 10907 * already younger than that). Otherwise, leave *YOUNGEST_MERGED_REV alone. 10908 */ 10909static svn_error_t * 10910find_youngest_merged_rev(svn_revnum_t *youngest_merged_rev, 10911 svn_mergeinfo_t target_history_as_mergeinfo, 10912 svn_mergeinfo_t source_mergeinfo, 10913 apr_pool_t *scratch_pool) 10914{ 10915 svn_mergeinfo_t explicit_source_target_history_intersection; 10916 10917 SVN_ERR(svn_mergeinfo_intersect2( 10918 &explicit_source_target_history_intersection, 10919 source_mergeinfo, target_history_as_mergeinfo, TRUE, 10920 scratch_pool, scratch_pool)); 10921 if (apr_hash_count(explicit_source_target_history_intersection)) 10922 { 10923 svn_revnum_t old_rev, young_rev; 10924 10925 /* Keep track of the youngest revision merged from target to source. */ 10926 SVN_ERR(svn_mergeinfo__get_range_endpoints( 10927 &young_rev, &old_rev, 10928 explicit_source_target_history_intersection, scratch_pool)); 10929 if (!SVN_IS_VALID_REVNUM(*youngest_merged_rev) 10930 || (young_rev > *youngest_merged_rev)) 10931 *youngest_merged_rev = young_rev; 10932 } 10933 10934 return SVN_NO_ERROR; 10935} 10936 10937/* Set *FILTERED_MERGEINFO_P to the parts of TARGET_HISTORY_AS_MERGEINFO 10938 * that are not present in the source branch. 10939 * 10940 * SOURCE_MERGEINFO is the explicit or inherited mergeinfo of the source 10941 * branch SOURCE_PATHREV. Extend SOURCE_MERGEINFO, modifying it in 10942 * place, to include the natural history (implicit mergeinfo) of 10943 * SOURCE_PATHREV. ### But make these additions in SCRATCH_POOL. 10944 * 10945 * SOURCE_RA_SESSION is an RA session open to the repository containing 10946 * SOURCE_PATHREV; it may be temporarily reparented within this function. 10947 * 10948 * ### [JAF] This function is named '..._subroutine' simply because I 10949 * factored it out based on code similarity, without knowing what it's 10950 * purpose is. We should clarify its purpose and choose a better name. 10951 */ 10952static svn_error_t * 10953find_unmerged_mergeinfo_subroutine(svn_mergeinfo_t *filtered_mergeinfo_p, 10954 svn_mergeinfo_t target_history_as_mergeinfo, 10955 svn_mergeinfo_t source_mergeinfo, 10956 const svn_client__pathrev_t *source_pathrev, 10957 svn_ra_session_t *source_ra_session, 10958 svn_client_ctx_t *ctx, 10959 apr_pool_t *result_pool, 10960 apr_pool_t *scratch_pool) 10961{ 10962 svn_mergeinfo_t source_history_as_mergeinfo; 10963 10964 /* Get the source path's natural history and merge it into source 10965 path's explicit or inherited mergeinfo. */ 10966 SVN_ERR(svn_client__get_history_as_mergeinfo( 10967 &source_history_as_mergeinfo, NULL /* has_rev_zero_history */, 10968 source_pathrev, source_pathrev->rev, SVN_INVALID_REVNUM, 10969 source_ra_session, ctx, scratch_pool)); 10970 SVN_ERR(svn_mergeinfo_merge2(source_mergeinfo, 10971 source_history_as_mergeinfo, 10972 scratch_pool, scratch_pool)); 10973 10974 /* Now source_mergeinfo represents everything we know about 10975 source_path's history. Now we need to know what part, if any, of the 10976 corresponding target's history is *not* part of source_path's total 10977 history; because it is neither shared history nor was it ever merged 10978 from the target to the source. */ 10979 SVN_ERR(svn_mergeinfo_remove2(filtered_mergeinfo_p, 10980 source_mergeinfo, 10981 target_history_as_mergeinfo, TRUE, 10982 result_pool, scratch_pool)); 10983 return SVN_NO_ERROR; 10984} 10985 10986/* Helper for calculate_left_hand_side() which produces a mergeinfo catalog 10987 describing what parts of of the reintegrate target have not previously been 10988 merged to the reintegrate source. 10989 10990 SOURCE_CATALOG is the collection of explicit mergeinfo on SOURCE_LOC and 10991 all its children, i.e. the mergeinfo catalog for the reintegrate source. 10992 10993 TARGET_HISTORY_HASH is a hash of (const char *) paths mapped to 10994 svn_mergeinfo_t representing the location history. Each of these 10995 path keys represent a path in the reintegrate target, relative to the 10996 repository root, which has explicit mergeinfo and/or is the reintegrate 10997 target itself. The svn_mergeinfo_t's contain the natural history of each 10998 path@TARGET_REV. Effectively this is the mergeinfo catalog on the 10999 reintegrate target. 11000 11001 YC_ANCESTOR_REV is the revision of the youngest common ancestor of the 11002 reintegrate source and the reintegrate target. 11003 11004 SOURCE_LOC is the reintegrate source. 11005 11006 SOURCE_RA_SESSION is a session opened to the URL of SOURCE_LOC 11007 and TARGET_RA_SESSION is open to TARGET->loc.url. 11008 11009 For each entry in TARGET_HISTORY_HASH check that the history it 11010 represents is contained in either the explicit mergeinfo for the 11011 corresponding path in SOURCE_CATALOG, the corresponding path's inherited 11012 mergeinfo (if no explicit mergeinfo for the path is found in 11013 SOURCE_CATALOG), or the corresponding path's natural history. Populate 11014 *UNMERGED_TO_SOURCE_CATALOG with the corresponding source paths mapped to 11015 the mergeinfo from the target's natural history which is *not* found. Also 11016 include any mergeinfo from SOURCE_CATALOG which explicitly describes the 11017 target's history but for which *no* entry was found in 11018 TARGET_HISTORY_HASH. 11019 11020 If no part of TARGET_HISTORY_HASH is found in SOURCE_CATALOG set 11021 *YOUNGEST_MERGED_REV to SVN_INVALID_REVNUM; otherwise set it to the youngest 11022 revision previously merged from the target to the source, and filter 11023 *UNMERGED_TO_SOURCE_CATALOG so that it contains no ranges greater than 11024 *YOUNGEST_MERGED_REV. 11025 11026 *UNMERGED_TO_SOURCE_CATALOG is (deeply) allocated in RESULT_POOL. 11027 SCRATCH_POOL is used for all temporary allocations. */ 11028static svn_error_t * 11029find_unmerged_mergeinfo(svn_mergeinfo_catalog_t *unmerged_to_source_catalog, 11030 svn_revnum_t *youngest_merged_rev, 11031 svn_revnum_t yc_ancestor_rev, 11032 svn_mergeinfo_catalog_t source_catalog, 11033 apr_hash_t *target_history_hash, 11034 const svn_client__pathrev_t *source_loc, 11035 const merge_target_t *target, 11036 svn_ra_session_t *source_ra_session, 11037 svn_ra_session_t *target_ra_session, 11038 svn_client_ctx_t *ctx, 11039 apr_pool_t *result_pool, 11040 apr_pool_t *scratch_pool) 11041{ 11042 const char *source_repos_rel_path 11043 = svn_client__pathrev_relpath(source_loc, scratch_pool); 11044 const char *target_repos_rel_path 11045 = svn_client__pathrev_relpath(&target->loc, scratch_pool); 11046 apr_hash_index_t *hi; 11047 svn_mergeinfo_catalog_t new_catalog = apr_hash_make(result_pool); 11048 apr_pool_t *iterpool = svn_pool_create(scratch_pool); 11049 11050 assert(session_url_is(source_ra_session, source_loc->url, scratch_pool)); 11051 assert(session_url_is(target_ra_session, target->loc.url, scratch_pool)); 11052 11053 *youngest_merged_rev = SVN_INVALID_REVNUM; 11054 11055 /* Examine the natural history of each path in the reintegrate target 11056 with explicit mergeinfo. */ 11057 for (hi = apr_hash_first(scratch_pool, target_history_hash); 11058 hi; 11059 hi = apr_hash_next(hi)) 11060 { 11061 const char *target_path = svn__apr_hash_index_key(hi); 11062 svn_mergeinfo_t target_history_as_mergeinfo = svn__apr_hash_index_val(hi); 11063 const char *path_rel_to_session 11064 = svn_relpath_skip_ancestor(target_repos_rel_path, target_path); 11065 const char *source_path; 11066 svn_client__pathrev_t *source_pathrev; 11067 svn_mergeinfo_t source_mergeinfo, filtered_mergeinfo; 11068 11069 svn_pool_clear(iterpool); 11070 11071 source_path = svn_relpath_join(source_repos_rel_path, 11072 path_rel_to_session, iterpool); 11073 source_pathrev = svn_client__pathrev_join_relpath( 11074 source_loc, path_rel_to_session, iterpool); 11075 11076 /* Remove any target history that is also part of the source's history, 11077 i.e. their common ancestry. By definition this has already been 11078 "merged" from the target to the source. If the source has explicit 11079 self referential mergeinfo it would intersect with the target's 11080 history below, making it appear that some merges had been done from 11081 the target to the source, when this might not actually be the case. */ 11082 SVN_ERR(svn_mergeinfo__filter_mergeinfo_by_ranges( 11083 &target_history_as_mergeinfo, target_history_as_mergeinfo, 11084 source_loc->rev, yc_ancestor_rev, TRUE, iterpool, iterpool)); 11085 11086 /* Look for any explicit mergeinfo on the source path corresponding to 11087 the target path. If we find any remove that from SOURCE_CATALOG. 11088 When this iteration over TARGET_HISTORY_HASH is complete all that 11089 should be left in SOURCE_CATALOG are subtrees that have explicit 11090 mergeinfo on the reintegrate source where there is no corresponding 11091 explicit mergeinfo on the reintegrate target. */ 11092 source_mergeinfo = svn_hash_gets(source_catalog, source_path); 11093 if (source_mergeinfo) 11094 { 11095 svn_hash_sets(source_catalog, source_path, NULL); 11096 11097 SVN_ERR(find_youngest_merged_rev(youngest_merged_rev, 11098 target_history_as_mergeinfo, 11099 source_mergeinfo, 11100 iterpool)); 11101 } 11102 else 11103 { 11104 /* There is no mergeinfo on source_path *or* source_path doesn't 11105 exist at all. If simply doesn't exist we can ignore it 11106 altogether. */ 11107 svn_node_kind_t kind; 11108 11109 SVN_ERR(svn_ra_check_path(source_ra_session, 11110 path_rel_to_session, 11111 source_loc->rev, &kind, iterpool)); 11112 if (kind == svn_node_none) 11113 continue; 11114 /* Else source_path does exist though it has no explicit mergeinfo. 11115 Find its inherited mergeinfo. If it doesn't have any then simply 11116 set source_mergeinfo to an empty hash. */ 11117 SVN_ERR(svn_client__get_repos_mergeinfo( 11118 &source_mergeinfo, source_ra_session, 11119 source_pathrev->url, source_pathrev->rev, 11120 svn_mergeinfo_inherited, FALSE /*squelch_incapable*/, 11121 iterpool)); 11122 if (!source_mergeinfo) 11123 source_mergeinfo = apr_hash_make(iterpool); 11124 } 11125 11126 /* Use scratch_pool rather than iterpool because filtered_mergeinfo 11127 is going into new_catalog below and needs to last to the end of 11128 this function. */ 11129 SVN_ERR(find_unmerged_mergeinfo_subroutine( 11130 &filtered_mergeinfo, target_history_as_mergeinfo, 11131 source_mergeinfo, source_pathrev, 11132 source_ra_session, ctx, scratch_pool, iterpool)); 11133 svn_hash_sets(new_catalog, apr_pstrdup(scratch_pool, source_path), 11134 filtered_mergeinfo); 11135 } 11136 11137 /* Are there any subtrees with explicit mergeinfo still left in the merge 11138 source where there was no explicit mergeinfo for the corresponding path 11139 in the merge target? If so, add the intersection of those path's 11140 mergeinfo and the corresponding target path's mergeinfo to 11141 new_catalog. */ 11142 for (hi = apr_hash_first(scratch_pool, source_catalog); 11143 hi; 11144 hi = apr_hash_next(hi)) 11145 { 11146 const char *source_path = svn__apr_hash_index_key(hi); 11147 const char *path_rel_to_session = 11148 svn_relpath_skip_ancestor(source_repos_rel_path, source_path); 11149 const char *source_url; 11150 svn_mergeinfo_t source_mergeinfo = svn__apr_hash_index_val(hi); 11151 svn_mergeinfo_t filtered_mergeinfo; 11152 svn_client__pathrev_t *target_pathrev; 11153 svn_mergeinfo_t target_history_as_mergeinfo; 11154 svn_error_t *err; 11155 11156 svn_pool_clear(iterpool); 11157 11158 source_url = svn_path_url_add_component2(source_loc->url, 11159 path_rel_to_session, iterpool); 11160 target_pathrev = svn_client__pathrev_join_relpath( 11161 &target->loc, path_rel_to_session, iterpool); 11162 err = svn_client__get_history_as_mergeinfo(&target_history_as_mergeinfo, 11163 NULL /* has_rev_zero_history */, 11164 target_pathrev, 11165 target->loc.rev, 11166 SVN_INVALID_REVNUM, 11167 target_ra_session, 11168 ctx, iterpool); 11169 if (err) 11170 { 11171 if (err->apr_err == SVN_ERR_FS_NOT_FOUND 11172 || err->apr_err == SVN_ERR_RA_DAV_REQUEST_FAILED) 11173 { 11174 /* This path with explicit mergeinfo in the source doesn't 11175 exist on the target. */ 11176 svn_error_clear(err); 11177 err = NULL; 11178 } 11179 else 11180 { 11181 return svn_error_trace(err); 11182 } 11183 } 11184 else 11185 { 11186 svn_client__pathrev_t *pathrev; 11187 11188 SVN_ERR(find_youngest_merged_rev(youngest_merged_rev, 11189 target_history_as_mergeinfo, 11190 source_mergeinfo, 11191 iterpool)); 11192 11193 /* Use scratch_pool rather than iterpool because filtered_mergeinfo 11194 is going into new_catalog below and needs to last to the end of 11195 this function. */ 11196 /* ### Why looking at SOURCE_url at TARGET_rev? */ 11197 SVN_ERR(svn_client__pathrev_create_with_session( 11198 &pathrev, source_ra_session, target->loc.rev, source_url, 11199 iterpool)); 11200 SVN_ERR(find_unmerged_mergeinfo_subroutine( 11201 &filtered_mergeinfo, target_history_as_mergeinfo, 11202 source_mergeinfo, pathrev, 11203 source_ra_session, ctx, scratch_pool, iterpool)); 11204 if (apr_hash_count(filtered_mergeinfo)) 11205 svn_hash_sets(new_catalog, 11206 apr_pstrdup(scratch_pool, source_path), 11207 filtered_mergeinfo); 11208 } 11209 } 11210 11211 /* Limit new_catalog to the youngest revisions previously merged from 11212 the target to the source. */ 11213 if (SVN_IS_VALID_REVNUM(*youngest_merged_rev)) 11214 SVN_ERR(svn_mergeinfo__filter_catalog_by_ranges(&new_catalog, 11215 new_catalog, 11216 *youngest_merged_rev, 11217 0, /* No oldest bound. */ 11218 TRUE, 11219 scratch_pool, 11220 scratch_pool)); 11221 11222 /* Make a shiny new copy before blowing away all the temporary pools. */ 11223 *unmerged_to_source_catalog = svn_mergeinfo_catalog_dup(new_catalog, 11224 result_pool); 11225 svn_pool_destroy(iterpool); 11226 return SVN_NO_ERROR; 11227} 11228 11229/* Helper for svn_client_merge_reintegrate() which calculates the 11230 'left hand side' of the underlying two-URL merge that a --reintegrate 11231 merge actually performs. If no merge should be performed, set 11232 *LEFT_P to NULL. 11233 11234 TARGET->abspath is the absolute working copy path of the reintegrate 11235 merge. 11236 11237 SOURCE_LOC is the reintegrate source. 11238 11239 SUBTREES_WITH_MERGEINFO is a hash of (const char *) absolute paths mapped 11240 to (svn_mergeinfo_t *) mergeinfo values for each working copy path with 11241 explicit mergeinfo in TARGET->abspath. Actually we only need to know the 11242 paths, not the mergeinfo. 11243 11244 TARGET->loc.rev is the working revision the entire WC tree rooted at 11245 TARGET is at. 11246 11247 Populate *UNMERGED_TO_SOURCE_CATALOG with the mergeinfo describing what 11248 parts of TARGET->loc have not been merged to SOURCE_LOC, up to the 11249 youngest revision ever merged from the TARGET->abspath to the source if 11250 such exists, see doc string for find_unmerged_mergeinfo(). 11251 11252 SOURCE_RA_SESSION is a session opened to the SOURCE_LOC 11253 and TARGET_RA_SESSION is open to TARGET->loc.url. 11254 11255 *LEFT_P, *MERGED_TO_SOURCE_CATALOG , and *UNMERGED_TO_SOURCE_CATALOG are 11256 allocated in RESULT_POOL. SCRATCH_POOL is used for all temporary 11257 allocations. */ 11258static svn_error_t * 11259calculate_left_hand_side(svn_client__pathrev_t **left_p, 11260 svn_mergeinfo_catalog_t *merged_to_source_catalog, 11261 svn_mergeinfo_catalog_t *unmerged_to_source_catalog, 11262 const merge_target_t *target, 11263 apr_hash_t *subtrees_with_mergeinfo, 11264 const svn_client__pathrev_t *source_loc, 11265 svn_ra_session_t *source_ra_session, 11266 svn_ra_session_t *target_ra_session, 11267 svn_client_ctx_t *ctx, 11268 apr_pool_t *result_pool, 11269 apr_pool_t *scratch_pool) 11270{ 11271 svn_mergeinfo_catalog_t mergeinfo_catalog, unmerged_catalog; 11272 apr_pool_t *iterpool = svn_pool_create(scratch_pool); 11273 apr_hash_index_t *hi; 11274 /* hash of paths mapped to arrays of svn_mergeinfo_t. */ 11275 apr_hash_t *target_history_hash = apr_hash_make(scratch_pool); 11276 svn_revnum_t youngest_merged_rev; 11277 svn_client__pathrev_t *yc_ancestor; 11278 11279 assert(session_url_is(source_ra_session, source_loc->url, scratch_pool)); 11280 assert(session_url_is(target_ra_session, target->loc.url, scratch_pool)); 11281 11282 /* Initialize our return variables. */ 11283 *left_p = NULL; 11284 11285 /* TARGET->abspath may not have explicit mergeinfo and thus may not be 11286 contained within SUBTREES_WITH_MERGEINFO. If this is the case then 11287 add a dummy item for TARGET->abspath so we get its history (i.e. implicit 11288 mergeinfo) below. */ 11289 if (!svn_hash_gets(subtrees_with_mergeinfo, target->abspath)) 11290 svn_hash_sets(subtrees_with_mergeinfo, target->abspath, 11291 apr_hash_make(result_pool)); 11292 11293 /* Get the history segments (as mergeinfo) for TARGET->abspath and any of 11294 its subtrees with explicit mergeinfo. */ 11295 for (hi = apr_hash_first(scratch_pool, subtrees_with_mergeinfo); 11296 hi; 11297 hi = apr_hash_next(hi)) 11298 { 11299 const char *local_abspath = svn__apr_hash_index_key(hi); 11300 svn_client__pathrev_t *target_child; 11301 const char *repos_relpath; 11302 svn_mergeinfo_t target_history_as_mergeinfo; 11303 11304 svn_pool_clear(iterpool); 11305 11306 /* Convert the absolute path with mergeinfo on it to a path relative 11307 to the session root. */ 11308 SVN_ERR(svn_wc__node_get_repos_info(NULL, &repos_relpath, NULL, NULL, 11309 ctx->wc_ctx, local_abspath, 11310 scratch_pool, iterpool)); 11311 target_child = svn_client__pathrev_create_with_relpath( 11312 target->loc.repos_root_url, target->loc.repos_uuid, 11313 target->loc.rev, repos_relpath, iterpool); 11314 SVN_ERR(svn_client__get_history_as_mergeinfo(&target_history_as_mergeinfo, 11315 NULL /* has_rev_zero_hist */, 11316 target_child, 11317 target->loc.rev, 11318 SVN_INVALID_REVNUM, 11319 target_ra_session, 11320 ctx, scratch_pool)); 11321 11322 svn_hash_sets(target_history_hash, repos_relpath, 11323 target_history_as_mergeinfo); 11324 } 11325 11326 /* Check that SOURCE_LOC and TARGET->loc are 11327 actually related, we can't reintegrate if they are not. Also 11328 get an initial value for the YCA revision number. */ 11329 SVN_ERR(svn_client__get_youngest_common_ancestor( 11330 &yc_ancestor, source_loc, &target->loc, target_ra_session, ctx, 11331 iterpool, iterpool)); 11332 if (! yc_ancestor) 11333 return svn_error_createf(SVN_ERR_CLIENT_NOT_READY_TO_MERGE, NULL, 11334 _("'%s@%ld' must be ancestrally related to " 11335 "'%s@%ld'"), source_loc->url, source_loc->rev, 11336 target->loc.url, target->loc.rev); 11337 11338 /* If the source revision is the same as the youngest common 11339 revision, then there can't possibly be any unmerged revisions 11340 that we need to apply to target. */ 11341 if (source_loc->rev == yc_ancestor->rev) 11342 { 11343 svn_pool_destroy(iterpool); 11344 return SVN_NO_ERROR; 11345 } 11346 11347 /* Get the mergeinfo from the source, including its descendants 11348 with differing explicit mergeinfo. */ 11349 SVN_ERR(svn_client__get_repos_mergeinfo_catalog( 11350 &mergeinfo_catalog, source_ra_session, 11351 source_loc->url, source_loc->rev, 11352 svn_mergeinfo_inherited, FALSE /* squelch_incapable */, 11353 TRUE /* include_descendants */, iterpool, iterpool)); 11354 11355 if (!mergeinfo_catalog) 11356 mergeinfo_catalog = apr_hash_make(iterpool); 11357 11358 *merged_to_source_catalog = svn_mergeinfo_catalog_dup(mergeinfo_catalog, 11359 result_pool); 11360 11361 /* Filter the source's mergeinfo catalog so that we are left with 11362 mergeinfo that describes what has *not* previously been merged from 11363 TARGET->loc to SOURCE_LOC. */ 11364 SVN_ERR(find_unmerged_mergeinfo(&unmerged_catalog, 11365 &youngest_merged_rev, 11366 yc_ancestor->rev, 11367 mergeinfo_catalog, 11368 target_history_hash, 11369 source_loc, 11370 target, 11371 source_ra_session, 11372 target_ra_session, 11373 ctx, 11374 iterpool, iterpool)); 11375 11376 /* Simplify unmerged_catalog through elision then make a copy in POOL. */ 11377 SVN_ERR(svn_client__elide_mergeinfo_catalog(unmerged_catalog, 11378 iterpool)); 11379 *unmerged_to_source_catalog = svn_mergeinfo_catalog_dup(unmerged_catalog, 11380 result_pool); 11381 11382 if (youngest_merged_rev == SVN_INVALID_REVNUM) 11383 { 11384 /* We never merged to the source. Just return the branch point. */ 11385 *left_p = svn_client__pathrev_dup(yc_ancestor, result_pool); 11386 } 11387 else 11388 { 11389 /* We've previously merged some or all of the target, up to 11390 youngest_merged_rev, to the source. Set 11391 *LEFT_P to cover the youngest part of this range. */ 11392 SVN_ERR(svn_client__repos_location(left_p, target_ra_session, 11393 &target->loc, youngest_merged_rev, 11394 ctx, result_pool, iterpool)); 11395 } 11396 11397 svn_pool_destroy(iterpool); 11398 return SVN_NO_ERROR; 11399} 11400 11401/* Determine the URLs and revisions needed to perform a reintegrate merge 11402 * from SOURCE_LOC into the working copy at TARGET. 11403 * 11404 * SOURCE_RA_SESSION and TARGET_RA_SESSION are RA sessions opened to the 11405 * URLs of SOURCE_LOC and TARGET->loc respectively. 11406 * 11407 * Set *SOURCE_P to 11408 * the source-left and source-right locations of the required merge. Set 11409 * *YC_ANCESTOR_P to the location of the youngest ancestor. 11410 * Any of these output pointers may be NULL if not wanted. 11411 * 11412 * See svn_client_find_reintegrate_merge() for other details. 11413 */ 11414static svn_error_t * 11415find_reintegrate_merge(merge_source_t **source_p, 11416 svn_client__pathrev_t **yc_ancestor_p, 11417 svn_ra_session_t *source_ra_session, 11418 const svn_client__pathrev_t *source_loc, 11419 svn_ra_session_t *target_ra_session, 11420 const merge_target_t *target, 11421 svn_client_ctx_t *ctx, 11422 apr_pool_t *result_pool, 11423 apr_pool_t *scratch_pool) 11424{ 11425 svn_client__pathrev_t *yc_ancestor; 11426 svn_client__pathrev_t *loc1; 11427 merge_source_t source; 11428 svn_mergeinfo_catalog_t unmerged_to_source_mergeinfo_catalog; 11429 svn_mergeinfo_catalog_t merged_to_source_mergeinfo_catalog; 11430 svn_error_t *err; 11431 apr_hash_t *subtrees_with_mergeinfo; 11432 11433 assert(session_url_is(source_ra_session, source_loc->url, scratch_pool)); 11434 assert(session_url_is(target_ra_session, target->loc.url, scratch_pool)); 11435 11436 /* As the WC tree is "pure", use its last-updated-to revision as 11437 the default revision for the left side of our merge, since that's 11438 what the repository sub-tree is required to be up to date with 11439 (with regard to the WC). */ 11440 /* ### Bogus/obsolete comment? */ 11441 11442 /* Can't reintegrate to or from the root of the repository. */ 11443 if (strcmp(source_loc->url, source_loc->repos_root_url) == 0 11444 || strcmp(target->loc.url, target->loc.repos_root_url) == 0) 11445 return svn_error_createf(SVN_ERR_CLIENT_NOT_READY_TO_MERGE, NULL, 11446 _("Neither the reintegrate source nor target " 11447 "can be the root of the repository")); 11448 11449 /* Find all the subtrees in TARGET_WCPATH that have explicit mergeinfo. */ 11450 err = get_wc_explicit_mergeinfo_catalog(&subtrees_with_mergeinfo, 11451 target->abspath, svn_depth_infinity, 11452 ctx, scratch_pool, scratch_pool); 11453 /* Issue #3896: If invalid mergeinfo in the reintegrate target 11454 prevents us from proceeding, then raise the best error possible. */ 11455 if (err && err->apr_err == SVN_ERR_CLIENT_INVALID_MERGEINFO_NO_MERGETRACKING) 11456 err = svn_error_quick_wrap(err, _("Reintegrate merge not possible")); 11457 SVN_ERR(err); 11458 11459 SVN_ERR(calculate_left_hand_side(&loc1, 11460 &merged_to_source_mergeinfo_catalog, 11461 &unmerged_to_source_mergeinfo_catalog, 11462 target, 11463 subtrees_with_mergeinfo, 11464 source_loc, 11465 source_ra_session, 11466 target_ra_session, 11467 ctx, 11468 scratch_pool, scratch_pool)); 11469 11470 /* Did calculate_left_hand_side() decide that there was no merge to 11471 be performed here? */ 11472 if (! loc1) 11473 { 11474 if (source_p) 11475 *source_p = NULL; 11476 if (yc_ancestor_p) 11477 *yc_ancestor_p = NULL; 11478 return SVN_NO_ERROR; 11479 } 11480 11481 source.loc1 = loc1; 11482 source.loc2 = source_loc; 11483 11484 /* If the target was moved after the source was branched from it, 11485 it is possible that the left URL differs from the target's current 11486 URL. If so, then adjust TARGET_RA_SESSION to point to the old URL. */ 11487 if (strcmp(source.loc1->url, target->loc.url)) 11488 SVN_ERR(svn_ra_reparent(target_ra_session, source.loc1->url, scratch_pool)); 11489 11490 SVN_ERR(svn_client__get_youngest_common_ancestor( 11491 &yc_ancestor, source.loc2, source.loc1, target_ra_session, 11492 ctx, scratch_pool, scratch_pool)); 11493 11494 if (! yc_ancestor) 11495 return svn_error_createf(SVN_ERR_CLIENT_NOT_READY_TO_MERGE, NULL, 11496 _("'%s@%ld' must be ancestrally related to " 11497 "'%s@%ld'"), 11498 source.loc1->url, source.loc1->rev, 11499 source.loc2->url, source.loc2->rev); 11500 11501 /* The source side of a reintegrate merge is not 'ancestral', except in 11502 * the degenerate case where source == YCA. */ 11503 source.ancestral = (loc1->rev == yc_ancestor->rev); 11504 11505 if (source.loc1->rev > yc_ancestor->rev) 11506 { 11507 /* Have we actually merged anything to the source from the 11508 target? If so, make sure we've merged a contiguous 11509 prefix. */ 11510 svn_mergeinfo_catalog_t final_unmerged_catalog = apr_hash_make(scratch_pool); 11511 11512 SVN_ERR(find_unsynced_ranges(source_loc, &target->loc, 11513 unmerged_to_source_mergeinfo_catalog, 11514 merged_to_source_mergeinfo_catalog, 11515 final_unmerged_catalog, 11516 target_ra_session, scratch_pool, 11517 scratch_pool)); 11518 11519 if (apr_hash_count(final_unmerged_catalog)) 11520 { 11521 svn_string_t *source_mergeinfo_cat_string; 11522 11523 SVN_ERR(svn_mergeinfo__catalog_to_formatted_string( 11524 &source_mergeinfo_cat_string, 11525 final_unmerged_catalog, 11526 " ", " Missing ranges: ", scratch_pool)); 11527 return svn_error_createf(SVN_ERR_CLIENT_NOT_READY_TO_MERGE, 11528 NULL, 11529 _("Reintegrate can only be used if " 11530 "revisions %ld through %ld were " 11531 "previously merged from %s to the " 11532 "reintegrate source, but this is " 11533 "not the case:\n%s"), 11534 yc_ancestor->rev + 1, source.loc2->rev, 11535 target->loc.url, 11536 source_mergeinfo_cat_string->data); 11537 } 11538 } 11539 11540 /* Left side: trunk@youngest-trunk-rev-merged-to-branch-at-specified-peg-rev 11541 * Right side: branch@specified-peg-revision */ 11542 if (source_p) 11543 *source_p = merge_source_dup(&source, result_pool); 11544 11545 if (yc_ancestor_p) 11546 *yc_ancestor_p = svn_client__pathrev_dup(yc_ancestor, result_pool); 11547 return SVN_NO_ERROR; 11548} 11549 11550/* Resolve the source and target locations and open RA sessions to them, and 11551 * perform some checks appropriate for a reintegrate merge. 11552 * 11553 * Set *SOURCE_RA_SESSION_P and *SOURCE_LOC_P to a new session and the 11554 * repository location of SOURCE_PATH_OR_URL at SOURCE_PEG_REVISION. Set 11555 * *TARGET_RA_SESSION_P and *TARGET_P to a new session and the repository 11556 * location of the WC at TARGET_ABSPATH. 11557 * 11558 * Throw a SVN_ERR_CLIENT_UNRELATED_RESOURCES error if the target WC node is 11559 * a locally added node or if the source and target are not in the same 11560 * repository. Throw a SVN_ERR_CLIENT_NOT_READY_TO_MERGE error if the 11561 * target WC is not at a single revision without switched subtrees and 11562 * without local mods. 11563 * 11564 * Allocate all the outputs in RESULT_POOL. 11565 */ 11566static svn_error_t * 11567open_reintegrate_source_and_target(svn_ra_session_t **source_ra_session_p, 11568 svn_client__pathrev_t **source_loc_p, 11569 svn_ra_session_t **target_ra_session_p, 11570 merge_target_t **target_p, 11571 const char *source_path_or_url, 11572 const svn_opt_revision_t *source_peg_revision, 11573 const char *target_abspath, 11574 svn_client_ctx_t *ctx, 11575 apr_pool_t *result_pool, 11576 apr_pool_t *scratch_pool) 11577{ 11578 svn_client__pathrev_t *source_loc; 11579 merge_target_t *target; 11580 11581 /* Open the target WC. A reintegrate merge requires the merge target to 11582 * reflect a subtree of the repository as found at a single revision. */ 11583 SVN_ERR(open_target_wc(&target, target_abspath, 11584 FALSE, FALSE, FALSE, 11585 ctx, scratch_pool, scratch_pool)); 11586 SVN_ERR(svn_client_open_ra_session2(target_ra_session_p, 11587 target->loc.url, target->abspath, 11588 ctx, result_pool, scratch_pool)); 11589 if (! target->loc.url) 11590 return svn_error_createf(SVN_ERR_CLIENT_UNRELATED_RESOURCES, NULL, 11591 _("Can't reintegrate into '%s' because it is " 11592 "locally added and therefore not related to " 11593 "the merge source"), 11594 svn_dirent_local_style(target->abspath, 11595 scratch_pool)); 11596 11597 SVN_ERR(svn_client__ra_session_from_path2( 11598 source_ra_session_p, &source_loc, 11599 source_path_or_url, NULL, source_peg_revision, source_peg_revision, 11600 ctx, result_pool)); 11601 11602 /* source_loc and target->loc are required to be in the same repository, 11603 as mergeinfo doesn't come into play for cross-repository merging. */ 11604 SVN_ERR(check_same_repos(source_loc, 11605 svn_dirent_local_style(source_path_or_url, 11606 scratch_pool), 11607 &target->loc, 11608 svn_dirent_local_style(target->abspath, 11609 scratch_pool), 11610 TRUE /* strict_urls */, scratch_pool)); 11611 11612 *source_loc_p = source_loc; 11613 *target_p = target; 11614 return SVN_NO_ERROR; 11615} 11616 11617/* The body of svn_client_merge_reintegrate(), which see for details. */ 11618static svn_error_t * 11619merge_reintegrate_locked(conflict_report_t **conflict_report, 11620 const char *source_path_or_url, 11621 const svn_opt_revision_t *source_peg_revision, 11622 const char *target_abspath, 11623 svn_boolean_t diff_ignore_ancestry, 11624 svn_boolean_t dry_run, 11625 const apr_array_header_t *merge_options, 11626 svn_client_ctx_t *ctx, 11627 apr_pool_t *result_pool, 11628 apr_pool_t *scratch_pool) 11629{ 11630 svn_ra_session_t *target_ra_session, *source_ra_session; 11631 merge_target_t *target; 11632 svn_client__pathrev_t *source_loc; 11633 merge_source_t *source; 11634 svn_client__pathrev_t *yc_ancestor; 11635 svn_boolean_t use_sleep = FALSE; 11636 svn_error_t *err; 11637 11638 SVN_ERR(open_reintegrate_source_and_target( 11639 &source_ra_session, &source_loc, &target_ra_session, &target, 11640 source_path_or_url, source_peg_revision, target_abspath, 11641 ctx, scratch_pool, scratch_pool)); 11642 11643 SVN_ERR(find_reintegrate_merge(&source, &yc_ancestor, 11644 source_ra_session, source_loc, 11645 target_ra_session, target, 11646 ctx, scratch_pool, scratch_pool)); 11647 11648 if (! source) 11649 { 11650 return SVN_NO_ERROR; 11651 } 11652 11653 /* Do the real merge! */ 11654 /* ### TODO(reint): Make sure that one isn't the same line ancestor 11655 ### of the other (what's erroneously referred to as "ancestrally 11656 ### related" in this source file). For now, we just say the source 11657 ### isn't "ancestral" even if it is (in the degenerate case where 11658 ### source-left equals YCA). */ 11659 source->ancestral = FALSE; 11660 err = merge_cousins_and_supplement_mergeinfo(conflict_report, 11661 &use_sleep, 11662 target, 11663 target_ra_session, 11664 source_ra_session, 11665 source, yc_ancestor, 11666 TRUE /* same_repos */, 11667 svn_depth_infinity, 11668 diff_ignore_ancestry, 11669 FALSE /* force_delete */, 11670 FALSE /* record_only */, 11671 dry_run, 11672 merge_options, 11673 ctx, 11674 result_pool, scratch_pool); 11675 11676 if (use_sleep) 11677 svn_io_sleep_for_timestamps(target_abspath, scratch_pool); 11678 11679 SVN_ERR(err); 11680 return SVN_NO_ERROR; 11681} 11682 11683svn_error_t * 11684svn_client_merge_reintegrate(const char *source_path_or_url, 11685 const svn_opt_revision_t *source_peg_revision, 11686 const char *target_wcpath, 11687 svn_boolean_t dry_run, 11688 const apr_array_header_t *merge_options, 11689 svn_client_ctx_t *ctx, 11690 apr_pool_t *pool) 11691{ 11692 const char *target_abspath, *lock_abspath; 11693 conflict_report_t *conflict_report; 11694 11695 SVN_ERR(get_target_and_lock_abspath(&target_abspath, &lock_abspath, 11696 target_wcpath, ctx, pool)); 11697 11698 if (!dry_run) 11699 SVN_WC__CALL_WITH_WRITE_LOCK( 11700 merge_reintegrate_locked(&conflict_report, 11701 source_path_or_url, source_peg_revision, 11702 target_abspath, 11703 FALSE /*diff_ignore_ancestry*/, 11704 dry_run, merge_options, ctx, pool, pool), 11705 ctx->wc_ctx, lock_abspath, FALSE /* lock_anchor */, pool); 11706 else 11707 SVN_ERR(merge_reintegrate_locked(&conflict_report, 11708 source_path_or_url, source_peg_revision, 11709 target_abspath, 11710 FALSE /*diff_ignore_ancestry*/, 11711 dry_run, merge_options, ctx, pool, pool)); 11712 11713 SVN_ERR(make_merge_conflict_error(conflict_report, pool)); 11714 return SVN_NO_ERROR; 11715} 11716 11717 11718/* The body of svn_client_merge_peg5(), which see for details. 11719 * 11720 * IGNORE_MERGEINFO and DIFF_IGNORE_ANCESTRY are as in do_merge(). 11721 */ 11722static svn_error_t * 11723merge_peg_locked(conflict_report_t **conflict_report, 11724 const char *source_path_or_url, 11725 const svn_opt_revision_t *source_peg_revision, 11726 const svn_rangelist_t *ranges_to_merge, 11727 const char *target_abspath, 11728 svn_depth_t depth, 11729 svn_boolean_t ignore_mergeinfo, 11730 svn_boolean_t diff_ignore_ancestry, 11731 svn_boolean_t force_delete, 11732 svn_boolean_t record_only, 11733 svn_boolean_t dry_run, 11734 svn_boolean_t allow_mixed_rev, 11735 const apr_array_header_t *merge_options, 11736 svn_client_ctx_t *ctx, 11737 apr_pool_t *result_pool, 11738 apr_pool_t *scratch_pool) 11739{ 11740 merge_target_t *target; 11741 svn_client__pathrev_t *source_loc; 11742 apr_array_header_t *merge_sources; 11743 svn_ra_session_t *ra_session; 11744 apr_pool_t *sesspool; 11745 svn_boolean_t use_sleep = FALSE; 11746 svn_error_t *err; 11747 svn_boolean_t same_repos; 11748 11749 SVN_ERR_ASSERT(svn_dirent_is_absolute(target_abspath)); 11750 11751 SVN_ERR(open_target_wc(&target, target_abspath, 11752 allow_mixed_rev, TRUE, TRUE, 11753 ctx, scratch_pool, scratch_pool)); 11754 11755 /* Create a short lived session pool */ 11756 sesspool = svn_pool_create(scratch_pool); 11757 11758 /* Open an RA session to our source URL, and determine its root URL. */ 11759 SVN_ERR(svn_client__ra_session_from_path2( 11760 &ra_session, &source_loc, 11761 source_path_or_url, NULL, source_peg_revision, source_peg_revision, 11762 ctx, sesspool)); 11763 11764 /* Normalize our merge sources. */ 11765 SVN_ERR(normalize_merge_sources(&merge_sources, source_path_or_url, 11766 source_loc, 11767 ranges_to_merge, ra_session, ctx, 11768 scratch_pool, scratch_pool)); 11769 11770 /* Check for same_repos. */ 11771 same_repos = is_same_repos(&target->loc, source_loc, TRUE /* strict_urls */); 11772 11773 /* Do the real merge! (We say with confidence that our merge 11774 sources are both ancestral and related.) */ 11775 err = do_merge(NULL, NULL, conflict_report, &use_sleep, 11776 merge_sources, target, ra_session, 11777 TRUE /*sources_related*/, same_repos, ignore_mergeinfo, 11778 diff_ignore_ancestry, force_delete, dry_run, 11779 record_only, NULL, FALSE, FALSE, depth, merge_options, 11780 ctx, result_pool, scratch_pool); 11781 11782 /* We're done with our RA session. */ 11783 svn_pool_destroy(sesspool); 11784 11785 if (use_sleep) 11786 svn_io_sleep_for_timestamps(target_abspath, scratch_pool); 11787 11788 SVN_ERR(err); 11789 return SVN_NO_ERROR; 11790} 11791 11792/* Details of an automatic merge. */ 11793typedef struct automatic_merge_t 11794{ 11795 svn_client__pathrev_t *yca, *base, *right, *target; 11796 svn_boolean_t is_reintegrate_like; 11797 svn_boolean_t allow_mixed_rev, allow_local_mods, allow_switched_subtrees; 11798} automatic_merge_t; 11799 11800static svn_error_t * 11801client_find_automatic_merge(automatic_merge_t **merge_p, 11802 const char *source_path_or_url, 11803 const svn_opt_revision_t *source_revision, 11804 const char *target_abspath, 11805 svn_boolean_t allow_mixed_rev, 11806 svn_boolean_t allow_local_mods, 11807 svn_boolean_t allow_switched_subtrees, 11808 svn_client_ctx_t *ctx, 11809 apr_pool_t *result_pool, 11810 apr_pool_t *scratch_pool); 11811 11812static svn_error_t * 11813do_automatic_merge_locked(conflict_report_t **conflict_report, 11814 const automatic_merge_t *merge, 11815 const char *target_abspath, 11816 svn_depth_t depth, 11817 svn_boolean_t diff_ignore_ancestry, 11818 svn_boolean_t force_delete, 11819 svn_boolean_t record_only, 11820 svn_boolean_t dry_run, 11821 const apr_array_header_t *merge_options, 11822 svn_client_ctx_t *ctx, 11823 apr_pool_t *result_pool, 11824 apr_pool_t *scratch_pool); 11825 11826svn_error_t * 11827svn_client_merge_peg5(const char *source_path_or_url, 11828 const apr_array_header_t *ranges_to_merge, 11829 const svn_opt_revision_t *source_peg_revision, 11830 const char *target_wcpath, 11831 svn_depth_t depth, 11832 svn_boolean_t ignore_mergeinfo, 11833 svn_boolean_t diff_ignore_ancestry, 11834 svn_boolean_t force_delete, 11835 svn_boolean_t record_only, 11836 svn_boolean_t dry_run, 11837 svn_boolean_t allow_mixed_rev, 11838 const apr_array_header_t *merge_options, 11839 svn_client_ctx_t *ctx, 11840 apr_pool_t *pool) 11841{ 11842 const char *target_abspath, *lock_abspath; 11843 conflict_report_t *conflict_report; 11844 11845 /* No ranges to merge? No problem. */ 11846 if (ranges_to_merge != NULL && ranges_to_merge->nelts == 0) 11847 return SVN_NO_ERROR; 11848 11849 SVN_ERR(get_target_and_lock_abspath(&target_abspath, &lock_abspath, 11850 target_wcpath, ctx, pool)); 11851 11852 /* Do an automatic merge if no revision ranges are specified. */ 11853 if (ranges_to_merge == NULL) 11854 { 11855 automatic_merge_t *merge; 11856 11857 if (ignore_mergeinfo) 11858 return svn_error_create(SVN_ERR_INCORRECT_PARAMS, NULL, 11859 _("Cannot merge automatically while " 11860 "ignoring mergeinfo")); 11861 11862 /* Find the details of the merge needed. */ 11863 SVN_ERR(client_find_automatic_merge( 11864 &merge, 11865 source_path_or_url, source_peg_revision, 11866 target_abspath, 11867 allow_mixed_rev, 11868 TRUE /*allow_local_mods*/, 11869 TRUE /*allow_switched_subtrees*/, 11870 ctx, pool, pool)); 11871 11872 if (!dry_run) 11873 SVN_WC__CALL_WITH_WRITE_LOCK( 11874 do_automatic_merge_locked(&conflict_report, 11875 merge, 11876 target_abspath, depth, 11877 diff_ignore_ancestry, 11878 force_delete, record_only, dry_run, 11879 merge_options, ctx, pool, pool), 11880 ctx->wc_ctx, lock_abspath, FALSE /* lock_anchor */, pool); 11881 else 11882 SVN_ERR(do_automatic_merge_locked(&conflict_report, 11883 merge, 11884 target_abspath, depth, 11885 diff_ignore_ancestry, 11886 force_delete, record_only, dry_run, 11887 merge_options, ctx, pool, pool)); 11888 } 11889 else if (!dry_run) 11890 SVN_WC__CALL_WITH_WRITE_LOCK( 11891 merge_peg_locked(&conflict_report, 11892 source_path_or_url, source_peg_revision, 11893 ranges_to_merge, 11894 target_abspath, depth, ignore_mergeinfo, 11895 diff_ignore_ancestry, 11896 force_delete, record_only, dry_run, 11897 allow_mixed_rev, merge_options, ctx, pool, pool), 11898 ctx->wc_ctx, lock_abspath, FALSE /* lock_anchor */, pool); 11899 else 11900 SVN_ERR(merge_peg_locked(&conflict_report, 11901 source_path_or_url, source_peg_revision, 11902 ranges_to_merge, 11903 target_abspath, depth, ignore_mergeinfo, 11904 diff_ignore_ancestry, 11905 force_delete, record_only, dry_run, 11906 allow_mixed_rev, merge_options, ctx, pool, pool)); 11907 11908 SVN_ERR(make_merge_conflict_error(conflict_report, pool)); 11909 return SVN_NO_ERROR; 11910} 11911 11912 11913/* The location-history of a branch. 11914 * 11915 * This structure holds the set of path-revisions occupied by a branch, 11916 * from an externally chosen 'tip' location back to its origin. The 11917 * 'tip' location is the youngest location that we are considering on 11918 * the branch. */ 11919typedef struct branch_history_t 11920{ 11921 /* The tip location of the branch. That is, the youngest location that's 11922 * in the repository and that we're considering. If we're considering a 11923 * target branch right up to an uncommitted WC, then this is the WC base 11924 * (pristine) location. */ 11925 svn_client__pathrev_t *tip; 11926 /* The location-segment history, as mergeinfo. */ 11927 svn_mergeinfo_t history; 11928 /* Whether the location-segment history reached as far as (necessarily 11929 the root path in) revision 0 -- a fact that can't be represented as 11930 mergeinfo. */ 11931 svn_boolean_t has_r0_history; 11932} branch_history_t; 11933 11934/* Return the location on BRANCH_HISTORY at revision REV, or NULL if none. */ 11935static svn_client__pathrev_t * 11936location_on_branch_at_rev(const branch_history_t *branch_history, 11937 svn_revnum_t rev, 11938 apr_pool_t *result_pool, 11939 apr_pool_t *scratch_pool) 11940{ 11941 apr_hash_index_t *hi; 11942 11943 for (hi = apr_hash_first(scratch_pool, branch_history->history); hi; 11944 hi = apr_hash_next(hi)) 11945 { 11946 const char *fspath = svn__apr_hash_index_key(hi); 11947 svn_rangelist_t *rangelist = svn__apr_hash_index_val(hi); 11948 int i; 11949 11950 for (i = 0; i < rangelist->nelts; i++) 11951 { 11952 svn_merge_range_t *r = APR_ARRAY_IDX(rangelist, i, svn_merge_range_t *); 11953 if (r->start < rev && rev <= r->end) 11954 { 11955 return svn_client__pathrev_create_with_relpath( 11956 branch_history->tip->repos_root_url, 11957 branch_history->tip->repos_uuid, 11958 rev, fspath + 1, result_pool); 11959 } 11960 } 11961 } 11962 return NULL; 11963} 11964 11965/* */ 11966typedef struct source_and_target_t 11967{ 11968 svn_client__pathrev_t *source; 11969 svn_ra_session_t *source_ra_session; 11970 branch_history_t source_branch; 11971 11972 merge_target_t *target; 11973 svn_ra_session_t *target_ra_session; 11974 branch_history_t target_branch; 11975 11976 /* Repos location of the youngest common ancestor of SOURCE and TARGET. */ 11977 svn_client__pathrev_t *yca; 11978} source_and_target_t; 11979 11980/* Set *INTERSECTION_P to the intersection of BRANCH_HISTORY with the 11981 * revision range OLDEST_REV to YOUNGEST_REV (inclusive). 11982 * 11983 * If the intersection is empty, the result will be a branch history object 11984 * containing an empty (not null) history. 11985 * 11986 * ### The 'tip' of the result is currently unchanged. 11987 */ 11988static svn_error_t * 11989branch_history_intersect_range(branch_history_t **intersection_p, 11990 const branch_history_t *branch_history, 11991 svn_revnum_t oldest_rev, 11992 svn_revnum_t youngest_rev, 11993 apr_pool_t *result_pool, 11994 apr_pool_t *scratch_pool) 11995{ 11996 branch_history_t *result = apr_palloc(result_pool, sizeof(*result)); 11997 11998 SVN_ERR_ASSERT(SVN_IS_VALID_REVNUM(oldest_rev)); 11999 SVN_ERR_ASSERT(SVN_IS_VALID_REVNUM(youngest_rev)); 12000 SVN_ERR_ASSERT(oldest_rev >= 1); 12001 /* Allow a just-empty range (oldest = youngest + 1) but not an 12002 * arbitrary reverse range (such as oldest = youngest + 2). */ 12003 SVN_ERR_ASSERT(oldest_rev <= youngest_rev + 1); 12004 12005 if (oldest_rev <= youngest_rev) 12006 { 12007 SVN_ERR(svn_mergeinfo__filter_mergeinfo_by_ranges( 12008 &result->history, branch_history->history, 12009 youngest_rev, oldest_rev - 1, TRUE /* include_range */, 12010 result_pool, scratch_pool)); 12011 result->history = svn_mergeinfo_dup(result->history, result_pool); 12012 } 12013 else 12014 { 12015 result->history = apr_hash_make(result_pool); 12016 } 12017 result->has_r0_history = FALSE; 12018 12019 /* ### TODO: Set RESULT->tip to the tip of the intersection. */ 12020 result->tip = svn_client__pathrev_dup(branch_history->tip, result_pool); 12021 12022 *intersection_p = result; 12023 return SVN_NO_ERROR; 12024} 12025 12026/* Set *OLDEST_P and *YOUNGEST_P to the oldest and youngest locations 12027 * (inclusive) along BRANCH. OLDEST_P and/or YOUNGEST_P may be NULL if not 12028 * wanted. 12029 */ 12030static svn_error_t * 12031branch_history_get_endpoints(svn_client__pathrev_t **oldest_p, 12032 svn_client__pathrev_t **youngest_p, 12033 const branch_history_t *branch, 12034 apr_pool_t *result_pool, 12035 apr_pool_t *scratch_pool) 12036{ 12037 svn_revnum_t youngest_rev, oldest_rev; 12038 12039 SVN_ERR(svn_mergeinfo__get_range_endpoints( 12040 &youngest_rev, &oldest_rev, 12041 branch->history, scratch_pool)); 12042 if (oldest_p) 12043 *oldest_p = location_on_branch_at_rev( 12044 branch, oldest_rev + 1, result_pool, scratch_pool); 12045 if (youngest_p) 12046 *youngest_p = location_on_branch_at_rev( 12047 branch, youngest_rev, result_pool, scratch_pool); 12048 return SVN_NO_ERROR; 12049} 12050 12051/* Implements the svn_log_entry_receiver_t interface. 12052 12053 Set *BATON to LOG_ENTRY->revision and return SVN_ERR_CEASE_INVOCATION. */ 12054static svn_error_t * 12055operative_rev_receiver(void *baton, 12056 svn_log_entry_t *log_entry, 12057 apr_pool_t *pool) 12058{ 12059 svn_revnum_t *operative_rev = baton; 12060 12061 *operative_rev = log_entry->revision; 12062 12063 /* We've found the youngest merged or oldest eligible revision, so 12064 we're done... 12065 12066 ...but wait, shouldn't we care if LOG_ENTRY->NON_INHERITABLE is 12067 true? Because if it is, then LOG_ENTRY->REVISION is only 12068 partially merged/elgibile! And our only caller, 12069 find_last_merged_location (via short_circuit_mergeinfo_log) is 12070 interested in *fully* merged revisions. That's all true, but if 12071 find_last_merged_location() finds the youngest merged revision it 12072 will also check for the oldest eligible revision. So in the case 12073 the youngest merged rev is non-inheritable, the *same* non-inheritable 12074 rev will be found as the oldest eligible rev -- and 12075 find_last_merged_location() handles that situation. */ 12076 return svn_error_create(SVN_ERR_CEASE_INVOCATION, NULL, NULL); 12077} 12078 12079/* Wrapper around svn_client__mergeinfo_log. All arguments are as per 12080 that private API. The discover_changed_paths, depth, and revprops args to 12081 svn_client__mergeinfo_log are always TRUE, svn_depth_infinity_t, 12082 and empty array respectively. 12083 12084 If RECEIVER raises a SVN_ERR_CEASE_INVOCATION error, but still sets 12085 *REVISION to a valid revnum, then clear the error. Otherwise return 12086 any error. */ 12087static svn_error_t* 12088short_circuit_mergeinfo_log(svn_mergeinfo_catalog_t *target_mergeinfo_cat, 12089 svn_boolean_t finding_merged, 12090 const char *target_path_or_url, 12091 const svn_opt_revision_t *target_peg_revision, 12092 const char *source_path_or_url, 12093 const svn_opt_revision_t *source_peg_revision, 12094 const svn_opt_revision_t *source_start_revision, 12095 const svn_opt_revision_t *source_end_revision, 12096 svn_log_entry_receiver_t receiver, 12097 svn_revnum_t *revision, 12098 svn_client_ctx_t *ctx, 12099 svn_ra_session_t *ra_session, 12100 apr_pool_t *result_pool, 12101 apr_pool_t *scratch_pool) 12102{ 12103 apr_array_header_t *revprops; 12104 svn_error_t *err; 12105 const char *session_url; 12106 12107 SVN_ERR(svn_ra_get_session_url(ra_session, &session_url, scratch_pool)); 12108 12109 revprops = apr_array_make(scratch_pool, 0, sizeof(const char *)); 12110 err = svn_client__mergeinfo_log(finding_merged, 12111 target_path_or_url, 12112 target_peg_revision, 12113 target_mergeinfo_cat, 12114 source_path_or_url, 12115 source_peg_revision, 12116 source_start_revision, 12117 source_end_revision, 12118 receiver, revision, 12119 TRUE, svn_depth_infinity, 12120 revprops, ctx, ra_session, 12121 result_pool, scratch_pool); 12122 12123 err = svn_error_compose_create( 12124 err, 12125 svn_ra_reparent(ra_session, session_url, scratch_pool)); 12126 12127 if (err) 12128 { 12129 /* We expect RECEIVER to short-circuit the (potentially expensive) log 12130 by raising an SVN_ERR_CEASE_INVOCATION -- see operative_rev_receiver. 12131 So we can ignore that error, but only as long as we actually found a 12132 valid revision. */ 12133 if (SVN_IS_VALID_REVNUM(*revision) 12134 && err->apr_err == SVN_ERR_CEASE_INVOCATION) 12135 { 12136 svn_error_clear(err); 12137 err = NULL; 12138 } 12139 else 12140 { 12141 return svn_error_trace(err); 12142 } 12143 } 12144 return SVN_NO_ERROR; 12145} 12146 12147/* Set *BASE_P to the last location on SOURCE_BRANCH such that all changes 12148 * on SOURCE_BRANCH after YCA up to and including *BASE_P have already 12149 * been fully merged into TARGET. 12150 * 12151 * *BASE_P TIP 12152 * o-------o-----------o--- SOURCE_BRANCH 12153 * / \ 12154 * -----o prev. \ 12155 * YCA \ merges \ 12156 * o-----------o----------- TARGET branch 12157 * 12158 * In terms of mergeinfo: 12159 * 12160 * Source a--... o=change, -=no-op revision 12161 * branch / \ 12162 * YCA --> o a---o---o---o---o--- d=delete, a=add-as-a-copy 12163 * 12164 * Eligible -.eee.eeeeeeeeeeeeeeeeeeee .=not a source branch location 12165 * 12166 * Tgt-mi -.mmm.mm-mm-------m------- m=merged to root of TARGET or 12167 * subtree of TARGET with no 12168 * operative changes outside of that 12169 * subtree, -=not merged 12170 * 12171 * Eligible -.---.--e--eeeeeee-eeeeeee 12172 * 12173 * Next --------^----------------- BASE is just before here. 12174 * 12175 * / \ 12176 * -----o prev. \ 12177 * YCA \ merges \ 12178 * o-----------o------------- 12179 * 12180 * If no revisions from SOURCE_BRANCH have been completely merged to TARGET, 12181 * then set *BASE_P to the YCA. 12182 */ 12183static svn_error_t * 12184find_last_merged_location(svn_client__pathrev_t **base_p, 12185 svn_client__pathrev_t *yca, 12186 const branch_history_t *source_branch, 12187 svn_client__pathrev_t *target, 12188 svn_client_ctx_t *ctx, 12189 svn_ra_session_t *ra_session, 12190 apr_pool_t *result_pool, 12191 apr_pool_t *scratch_pool) 12192{ 12193 svn_opt_revision_t source_peg_rev, source_start_rev, source_end_rev, 12194 target_opt_rev; 12195 svn_revnum_t youngest_merged_rev = SVN_INVALID_REVNUM; 12196 svn_mergeinfo_catalog_t target_mergeinfo_cat = NULL; 12197 12198 source_peg_rev.kind = svn_opt_revision_number; 12199 source_peg_rev.value.number = source_branch->tip->rev; 12200 source_start_rev.kind = svn_opt_revision_number; 12201 source_start_rev.value.number = yca->rev; 12202 source_end_rev.kind = svn_opt_revision_number; 12203 source_end_rev.value.number = source_branch->tip->rev; 12204 target_opt_rev.kind = svn_opt_revision_number; 12205 target_opt_rev.value.number = target->rev; 12206 12207 /* Find the youngest revision fully merged from SOURCE_BRANCH to TARGET, 12208 if such a revision exists. */ 12209 SVN_ERR(short_circuit_mergeinfo_log(&target_mergeinfo_cat, 12210 TRUE, /* Find merged */ 12211 target->url, &target_opt_rev, 12212 source_branch->tip->url, 12213 &source_peg_rev, 12214 &source_end_rev, &source_start_rev, 12215 operative_rev_receiver, 12216 &youngest_merged_rev, 12217 ctx, ra_session, 12218 result_pool, scratch_pool)); 12219 12220 if (!SVN_IS_VALID_REVNUM(youngest_merged_rev)) 12221 { 12222 /* No revisions have been completely merged from SOURCE_BRANCH to 12223 TARGET so the base for the next merge is the YCA. */ 12224 *base_p = yca; 12225 } 12226 else 12227 { 12228 /* One or more revisions have already been completely merged from 12229 SOURCE_BRANCH to TARGET, now find the oldest revision, older 12230 than the youngest merged revision, which is still eligible to 12231 be merged, if such exists. */ 12232 branch_history_t *contiguous_source; 12233 svn_revnum_t base_rev; 12234 svn_revnum_t oldest_eligible_rev = SVN_INVALID_REVNUM; 12235 12236 /* If the only revisions eligible are younger than the youngest merged 12237 revision we can simply assume that the youngest eligible revision 12238 is the youngest merged revision. Obviously this may not be true! 12239 The revisions between the youngest merged revision and the tip of 12240 the branch may have several inoperative revisions -- they may *all* 12241 be inoperative revisions! But for the purpose of this function 12242 (i.e. finding the youngest revision after the YCA where all revs have 12243 been merged) that doesn't matter. */ 12244 source_end_rev.value.number = youngest_merged_rev; 12245 SVN_ERR(short_circuit_mergeinfo_log(&target_mergeinfo_cat, 12246 FALSE, /* Find eligible */ 12247 target->url, &target_opt_rev, 12248 source_branch->tip->url, 12249 &source_peg_rev, 12250 &source_start_rev, &source_end_rev, 12251 operative_rev_receiver, 12252 &oldest_eligible_rev, 12253 ctx, ra_session, 12254 scratch_pool, scratch_pool)); 12255 12256 /* If there are revisions eligible for merging, use the oldest one 12257 to calculate the base. Otherwise there are no operative revisions 12258 to merge and we can simple set the base to the youngest revision 12259 already merged. */ 12260 if (SVN_IS_VALID_REVNUM(oldest_eligible_rev)) 12261 base_rev = oldest_eligible_rev - 1; 12262 else 12263 base_rev = youngest_merged_rev; 12264 12265 /* Find the branch location just before the oldest eligible rev. 12266 (We can't just use the base revs calculated above because the branch 12267 might have a gap there.) */ 12268 SVN_ERR(branch_history_intersect_range(&contiguous_source, 12269 source_branch, yca->rev, 12270 base_rev, 12271 scratch_pool, scratch_pool)); 12272 SVN_ERR(branch_history_get_endpoints(NULL, base_p, contiguous_source, 12273 result_pool, scratch_pool)); 12274 } 12275 12276 return SVN_NO_ERROR; 12277} 12278 12279/* Find a merge base location on the target branch, like in a sync 12280 * merge. 12281 * 12282 * BASE S_T->source 12283 * o-------o-----------o--- 12284 * / \ \ 12285 * -----o prev. \ \ this 12286 * YCA \ merge \ \ merge 12287 * o-----------o-----------o 12288 * S_T->target 12289 * 12290 * Set *BASE_P to BASE, the youngest location in the history of S_T->source 12291 * (at or after the YCA) at which all revisions up to BASE are effectively 12292 * merged into S_T->target. 12293 * 12294 * If no locations on the history of S_T->source are effectively merged to 12295 * S_T->target, set *BASE_P to the YCA. 12296 */ 12297static svn_error_t * 12298find_base_on_source(svn_client__pathrev_t **base_p, 12299 source_and_target_t *s_t, 12300 svn_client_ctx_t *ctx, 12301 apr_pool_t *result_pool, 12302 apr_pool_t *scratch_pool) 12303{ 12304 SVN_ERR(find_last_merged_location(base_p, 12305 s_t->yca, 12306 &s_t->source_branch, 12307 s_t->target_branch.tip, 12308 ctx, 12309 s_t->source_ra_session, 12310 result_pool, scratch_pool)); 12311 return SVN_NO_ERROR; 12312} 12313 12314/* Find a merge base location on the target branch, like in a reintegrate 12315 * merge. 12316 * 12317 * S_T->source 12318 * o-----------o-------o--- 12319 * / prev. / \ 12320 * -----o merge / \ this 12321 * YCA \ / \ merge 12322 * o-------o---------------o 12323 * BASE S_T->target 12324 * 12325 * Set *BASE_P to BASE, the youngest location in the history of S_T->target 12326 * (at or after the YCA) at which all revisions up to BASE are effectively 12327 * merged into S_T->source. 12328 * 12329 * If no locations on the history of S_T->target are effectively merged to 12330 * S_T->source, set *BASE_P to the YCA. 12331 */ 12332static svn_error_t * 12333find_base_on_target(svn_client__pathrev_t **base_p, 12334 source_and_target_t *s_t, 12335 svn_client_ctx_t *ctx, 12336 apr_pool_t *result_pool, 12337 apr_pool_t *scratch_pool) 12338{ 12339 SVN_ERR(find_last_merged_location(base_p, 12340 s_t->yca, 12341 &s_t->target_branch, 12342 s_t->source, 12343 ctx, 12344 s_t->target_ra_session, 12345 result_pool, scratch_pool)); 12346 12347 return SVN_NO_ERROR; 12348} 12349 12350/* The body of client_find_automatic_merge(), which see. 12351 */ 12352static svn_error_t * 12353find_automatic_merge(svn_client__pathrev_t **base_p, 12354 svn_boolean_t *is_reintegrate_like, 12355 source_and_target_t *s_t, 12356 svn_client_ctx_t *ctx, 12357 apr_pool_t *result_pool, 12358 apr_pool_t *scratch_pool) 12359{ 12360 svn_client__pathrev_t *base_on_source, *base_on_target; 12361 12362 /* Get the location-history of each branch. */ 12363 s_t->source_branch.tip = s_t->source; 12364 SVN_ERR(svn_client__get_history_as_mergeinfo( 12365 &s_t->source_branch.history, &s_t->source_branch.has_r0_history, 12366 s_t->source, SVN_INVALID_REVNUM, SVN_INVALID_REVNUM, 12367 s_t->source_ra_session, ctx, scratch_pool)); 12368 s_t->target_branch.tip = &s_t->target->loc; 12369 SVN_ERR(svn_client__get_history_as_mergeinfo( 12370 &s_t->target_branch.history, &s_t->target_branch.has_r0_history, 12371 &s_t->target->loc, SVN_INVALID_REVNUM, SVN_INVALID_REVNUM, 12372 s_t->target_ra_session, ctx, scratch_pool)); 12373 12374 SVN_ERR(svn_client__calc_youngest_common_ancestor( 12375 &s_t->yca, s_t->source, s_t->source_branch.history, 12376 s_t->source_branch.has_r0_history, 12377 &s_t->target->loc, s_t->target_branch.history, 12378 s_t->target_branch.has_r0_history, 12379 result_pool, scratch_pool)); 12380 12381 if (! s_t->yca) 12382 return svn_error_createf(SVN_ERR_CLIENT_NOT_READY_TO_MERGE, NULL, 12383 _("'%s@%ld' must be ancestrally related to " 12384 "'%s@%ld'"), 12385 s_t->source->url, s_t->source->rev, 12386 s_t->target->loc.url, s_t->target->loc.rev); 12387 12388 /* Find the latest revision of A synced to B and the latest 12389 * revision of B synced to A. 12390 * 12391 * base_on_source = youngest_complete_synced_point(source, target) 12392 * base_on_target = youngest_complete_synced_point(target, source) 12393 */ 12394 SVN_ERR(find_base_on_source(&base_on_source, s_t, 12395 ctx, scratch_pool, scratch_pool)); 12396 SVN_ERR(find_base_on_target(&base_on_target, s_t, 12397 ctx, scratch_pool, scratch_pool)); 12398 12399 /* Choose a base. */ 12400 if (base_on_source->rev >= base_on_target->rev) 12401 { 12402 *base_p = base_on_source; 12403 *is_reintegrate_like = FALSE; 12404 } 12405 else 12406 { 12407 *base_p = base_on_target; 12408 *is_reintegrate_like = TRUE; 12409 } 12410 12411 return SVN_NO_ERROR; 12412} 12413 12414/** Find out what kind of automatic merge would be needed, when the target 12415 * is only known as a repository location rather than a WC. 12416 * 12417 * Like find_automatic_merge() except that the target is 12418 * specified by @a target_path_or_url at @a target_revision, which must 12419 * refer to a repository location, instead of by a WC path argument. 12420 */ 12421static svn_error_t * 12422find_automatic_merge_no_wc(automatic_merge_t **merge_p, 12423 const char *source_path_or_url, 12424 const svn_opt_revision_t *source_revision, 12425 const char *target_path_or_url, 12426 const svn_opt_revision_t *target_revision, 12427 svn_client_ctx_t *ctx, 12428 apr_pool_t *result_pool, 12429 apr_pool_t *scratch_pool) 12430{ 12431 source_and_target_t *s_t = apr_palloc(scratch_pool, sizeof(*s_t)); 12432 svn_client__pathrev_t *target_loc; 12433 automatic_merge_t *merge = apr_palloc(result_pool, sizeof(*merge)); 12434 12435 /* Source */ 12436 SVN_ERR(svn_client__ra_session_from_path2( 12437 &s_t->source_ra_session, &s_t->source, 12438 source_path_or_url, NULL, source_revision, source_revision, 12439 ctx, result_pool)); 12440 12441 /* Target */ 12442 SVN_ERR(svn_client__ra_session_from_path2( 12443 &s_t->target_ra_session, &target_loc, 12444 target_path_or_url, NULL, target_revision, target_revision, 12445 ctx, result_pool)); 12446 s_t->target = apr_palloc(scratch_pool, sizeof(*s_t->target)); 12447 s_t->target->abspath = NULL; /* indicate the target is not a WC */ 12448 s_t->target->loc = *target_loc; 12449 12450 SVN_ERR(find_automatic_merge(&merge->base, &merge->is_reintegrate_like, s_t, 12451 ctx, result_pool, scratch_pool)); 12452 12453 merge->right = s_t->source; 12454 merge->target = &s_t->target->loc; 12455 merge->yca = s_t->yca; 12456 *merge_p = merge; 12457 12458 return SVN_NO_ERROR; 12459} 12460 12461/* Find the information needed to merge all unmerged changes from a source 12462 * branch into a target branch. 12463 * 12464 * Set @a *merge_p to the information needed to merge all unmerged changes 12465 * (up to @a source_revision) from the source branch @a source_path_or_url 12466 * at @a source_revision into the target WC at @a target_abspath. 12467 * 12468 * The flags @a allow_mixed_rev, @a allow_local_mods and 12469 * @a allow_switched_subtrees enable merging into a WC that is in any or all 12470 * of the states described by their names, but only if this function decides 12471 * that the merge will be in the same direction as the last automatic merge. 12472 * If, on the other hand, the last automatic merge was in the opposite 12473 * direction, then such states of the WC are not allowed regardless 12474 * of these flags. This function merely records these flags in the 12475 * @a *merge_p structure; do_automatic_merge_locked() checks the WC 12476 * state for compliance. 12477 * 12478 * Allocate the @a *merge_p structure in @a result_pool. 12479 */ 12480static svn_error_t * 12481client_find_automatic_merge(automatic_merge_t **merge_p, 12482 const char *source_path_or_url, 12483 const svn_opt_revision_t *source_revision, 12484 const char *target_abspath, 12485 svn_boolean_t allow_mixed_rev, 12486 svn_boolean_t allow_local_mods, 12487 svn_boolean_t allow_switched_subtrees, 12488 svn_client_ctx_t *ctx, 12489 apr_pool_t *result_pool, 12490 apr_pool_t *scratch_pool) 12491{ 12492 source_and_target_t *s_t = apr_palloc(result_pool, sizeof(*s_t)); 12493 automatic_merge_t *merge = apr_palloc(result_pool, sizeof(*merge)); 12494 12495 /* "Open" the target WC. Check the target WC for mixed-rev, local mods and 12496 * switched subtrees yet to faster exit and notify user before contacting 12497 * with server. After we find out what kind of merge is required, then if a 12498 * reintegrate-like merge is required we'll do the stricter checks, in 12499 * do_automatic_merge_locked(). */ 12500 SVN_ERR(open_target_wc(&s_t->target, target_abspath, 12501 allow_mixed_rev, 12502 allow_local_mods, 12503 allow_switched_subtrees, 12504 ctx, result_pool, scratch_pool)); 12505 12506 /* Open RA sessions to the source and target trees. */ 12507 SVN_ERR(svn_client_open_ra_session2(&s_t->target_ra_session, 12508 s_t->target->loc.url, 12509 s_t->target->abspath, 12510 ctx, result_pool, scratch_pool)); 12511 /* ### check for null URL (i.e. added path) here, like in reintegrate? */ 12512 SVN_ERR(svn_client__ra_session_from_path2( 12513 &s_t->source_ra_session, &s_t->source, 12514 source_path_or_url, NULL, source_revision, source_revision, 12515 ctx, result_pool)); 12516 12517 /* Check source is in same repos as target. */ 12518 SVN_ERR(check_same_repos(s_t->source, source_path_or_url, 12519 &s_t->target->loc, target_abspath, 12520 TRUE /* strict_urls */, scratch_pool)); 12521 12522 SVN_ERR(find_automatic_merge(&merge->base, &merge->is_reintegrate_like, s_t, 12523 ctx, result_pool, scratch_pool)); 12524 merge->yca = s_t->yca; 12525 merge->right = s_t->source; 12526 merge->allow_mixed_rev = allow_mixed_rev; 12527 merge->allow_local_mods = allow_local_mods; 12528 merge->allow_switched_subtrees = allow_switched_subtrees; 12529 12530 *merge_p = merge; 12531 12532 /* TODO: Close the source and target sessions here? */ 12533 12534 return SVN_NO_ERROR; 12535} 12536 12537/* Perform an automatic merge, given the information in MERGE which 12538 * must have come from calling client_find_automatic_merge(). 12539 * 12540 * Four locations are inputs: YCA, BASE, RIGHT, TARGET, as shown 12541 * depending on whether the base is on the source branch or the target 12542 * branch of this merge. 12543 * 12544 * RIGHT (is_reintegrate_like) 12545 * o-----------o-------o--- 12546 * / prev. / \ 12547 * -----o merge / \ this 12548 * YCA \ / \ merge 12549 * o-------o---------------o 12550 * BASE TARGET 12551 * 12552 * or 12553 * 12554 * BASE RIGHT (! is_reintegrate_like) 12555 * o-------o-----------o--- 12556 * / \ \ 12557 * -----o prev. \ \ this 12558 * YCA \ merge \ \ merge 12559 * o-----------o-----------o 12560 * TARGET 12561 * 12562 * ### TODO: The reintegrate-like code path does not yet 12563 * eliminate already-cherry-picked revisions from the source. 12564 */ 12565static svn_error_t * 12566do_automatic_merge_locked(conflict_report_t **conflict_report, 12567 const automatic_merge_t *merge, 12568 const char *target_abspath, 12569 svn_depth_t depth, 12570 svn_boolean_t diff_ignore_ancestry, 12571 svn_boolean_t force_delete, 12572 svn_boolean_t record_only, 12573 svn_boolean_t dry_run, 12574 const apr_array_header_t *merge_options, 12575 svn_client_ctx_t *ctx, 12576 apr_pool_t *result_pool, 12577 apr_pool_t *scratch_pool) 12578{ 12579 merge_target_t *target; 12580 svn_boolean_t reintegrate_like = merge->is_reintegrate_like; 12581 svn_boolean_t use_sleep = FALSE; 12582 svn_error_t *err; 12583 12584 SVN_ERR(open_target_wc(&target, target_abspath, 12585 merge->allow_mixed_rev && ! reintegrate_like, 12586 merge->allow_local_mods && ! reintegrate_like, 12587 merge->allow_switched_subtrees && ! reintegrate_like, 12588 ctx, scratch_pool, scratch_pool)); 12589 12590 if (reintegrate_like) 12591 { 12592 merge_source_t source; 12593 svn_ra_session_t *base_ra_session = NULL; 12594 svn_ra_session_t *right_ra_session = NULL; 12595 svn_ra_session_t *target_ra_session = NULL; 12596 12597 if (record_only) 12598 return svn_error_create(SVN_ERR_INCORRECT_PARAMS, NULL, 12599 _("The required merge is reintegrate-like, " 12600 "and the record-only option " 12601 "cannot be used with this kind of merge")); 12602 12603 if (depth != svn_depth_unknown) 12604 return svn_error_create(SVN_ERR_INCORRECT_PARAMS, NULL, 12605 _("The required merge is reintegrate-like, " 12606 "and the depth option " 12607 "cannot be used with this kind of merge")); 12608 12609 if (force_delete) 12610 return svn_error_create(SVN_ERR_INCORRECT_PARAMS, NULL, 12611 _("The required merge is reintegrate-like, " 12612 "and the force_delete option " 12613 "cannot be used with this kind of merge")); 12614 12615 SVN_ERR(ensure_ra_session_url(&base_ra_session, merge->base->url, 12616 target->abspath, ctx, scratch_pool)); 12617 SVN_ERR(ensure_ra_session_url(&right_ra_session, merge->right->url, 12618 target->abspath, ctx, scratch_pool)); 12619 SVN_ERR(ensure_ra_session_url(&target_ra_session, target->loc.url, 12620 target->abspath, ctx, scratch_pool)); 12621 12622 /* Check for and reject any abnormalities -- such as revisions that 12623 * have not yet been merged in the opposite direction -- that a 12624 * 'reintegrate' merge would have rejected. */ 12625 { 12626 merge_source_t *source2; 12627 12628 SVN_ERR(find_reintegrate_merge(&source2, NULL, 12629 right_ra_session, merge->right, 12630 target_ra_session, target, 12631 ctx, scratch_pool, scratch_pool)); 12632 } 12633 12634 source.loc1 = merge->base; 12635 source.loc2 = merge->right; 12636 source.ancestral = ! merge->is_reintegrate_like; 12637 12638 err = merge_cousins_and_supplement_mergeinfo(conflict_report, 12639 &use_sleep, 12640 target, 12641 base_ra_session, 12642 right_ra_session, 12643 &source, merge->yca, 12644 TRUE /* same_repos */, 12645 depth, 12646 FALSE /*diff_ignore_ancestry*/, 12647 force_delete, record_only, 12648 dry_run, 12649 merge_options, 12650 ctx, 12651 result_pool, scratch_pool); 12652 } 12653 else /* ! merge->is_reintegrate_like */ 12654 { 12655 /* Ignoring the base that we found, we pass the YCA instead and let 12656 do_merge() work out which subtrees need which revision ranges to 12657 be merged. This enables do_merge() to fill in revision-range 12658 gaps that are older than the base that we calculated (which is 12659 for the root path of the merge). 12660 12661 An improvement would be to change find_automatic_merge() to 12662 find the base for each sutree, and then here use the oldest base 12663 among all subtrees. */ 12664 apr_array_header_t *merge_sources; 12665 svn_ra_session_t *ra_session = NULL; 12666 12667 /* Normalize our merge sources, do_merge() requires this. See the 12668 'MERGEINFO MERGE SOURCE NORMALIZATION' global comment. */ 12669 SVN_ERR(ensure_ra_session_url(&ra_session, merge->right->url, 12670 target->abspath, ctx, scratch_pool)); 12671 SVN_ERR(normalize_merge_sources_internal( 12672 &merge_sources, merge->right, 12673 svn_rangelist__initialize(merge->yca->rev, merge->right->rev, TRUE, 12674 scratch_pool), 12675 ra_session, ctx, scratch_pool, scratch_pool)); 12676 12677 err = do_merge(NULL, NULL, conflict_report, &use_sleep, 12678 merge_sources, target, ra_session, 12679 TRUE /*related*/, TRUE /*same_repos*/, 12680 FALSE /*ignore_mergeinfo*/, diff_ignore_ancestry, 12681 force_delete, dry_run, 12682 record_only, NULL, FALSE, FALSE, depth, merge_options, 12683 ctx, result_pool, scratch_pool); 12684 } 12685 12686 if (use_sleep) 12687 svn_io_sleep_for_timestamps(target_abspath, scratch_pool); 12688 12689 SVN_ERR(err); 12690 12691 return SVN_NO_ERROR; 12692} 12693 12694svn_error_t * 12695svn_client_get_merging_summary(svn_boolean_t *needs_reintegration, 12696 const char **yca_url, svn_revnum_t *yca_rev, 12697 const char **base_url, svn_revnum_t *base_rev, 12698 const char **right_url, svn_revnum_t *right_rev, 12699 const char **target_url, svn_revnum_t *target_rev, 12700 const char **repos_root_url, 12701 const char *source_path_or_url, 12702 const svn_opt_revision_t *source_revision, 12703 const char *target_path_or_url, 12704 const svn_opt_revision_t *target_revision, 12705 svn_client_ctx_t *ctx, 12706 apr_pool_t *result_pool, 12707 apr_pool_t *scratch_pool) 12708{ 12709 svn_boolean_t target_is_wc; 12710 automatic_merge_t *merge; 12711 12712 target_is_wc = (! svn_path_is_url(target_path_or_url)) 12713 && (target_revision->kind == svn_opt_revision_unspecified 12714 || target_revision->kind == svn_opt_revision_working); 12715 if (target_is_wc) 12716 SVN_ERR(client_find_automatic_merge( 12717 &merge, 12718 source_path_or_url, source_revision, 12719 target_path_or_url, 12720 TRUE, TRUE, TRUE, /* allow_* */ 12721 ctx, scratch_pool, scratch_pool)); 12722 else 12723 SVN_ERR(find_automatic_merge_no_wc( 12724 &merge, 12725 source_path_or_url, source_revision, 12726 target_path_or_url, target_revision, 12727 ctx, scratch_pool, scratch_pool)); 12728 12729 if (needs_reintegration) 12730 *needs_reintegration = merge->is_reintegrate_like; 12731 if (yca_url) 12732 *yca_url = apr_pstrdup(result_pool, merge->yca->url); 12733 if (yca_rev) 12734 *yca_rev = merge->yca->rev; 12735 if (base_url) 12736 *base_url = apr_pstrdup(result_pool, merge->base->url); 12737 if (base_rev) 12738 *base_rev = merge->base->rev; 12739 if (right_url) 12740 *right_url = apr_pstrdup(result_pool, merge->right->url); 12741 if (right_rev) 12742 *right_rev = merge->right->rev; 12743 if (target_url) 12744 *target_url = apr_pstrdup(result_pool, merge->target->url); 12745 if (target_rev) 12746 *target_rev = merge->target->rev; 12747 if (repos_root_url) 12748 *repos_root_url = apr_pstrdup(result_pool, merge->yca->repos_root_url); 12749 12750 return SVN_NO_ERROR; 12751} 12752