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