Alien-SVN

 view release on metacpan or  search on metacpan

src/subversion/subversion/libsvn_client/merge.c  view on Meta::CPAN

  const apr_array_header_t *children_with_mergeinfo,
  svn_boolean_t path_is_own_ancestor,
  const char *local_abspath)
{
  int i;
  svn_client__merge_path_t *nearest_ancestor = NULL;

  *start = SVN_INVALID_REVNUM;
  *end = SVN_INVALID_REVNUM;

  SVN_ERR_ASSERT_NO_RETURN(children_with_mergeinfo != NULL);

  for (i = children_with_mergeinfo->nelts - 1; i >= 0 ; i--)
    {
      svn_client__merge_path_t *child =
        APR_ARRAY_IDX(children_with_mergeinfo, i, svn_client__merge_path_t *);

      if (svn_dirent_is_ancestor(child->abspath, local_abspath)
          && (path_is_own_ancestor
              || strcmp(child->abspath, local_abspath) != 0))
        {
          if (nearest_ancestor == NULL)
            {
              /* Found an ancestor. */
              nearest_ancestor = child;

              if (child->remaining_ranges)
                {
                  svn_merge_range_t *r1 = APR_ARRAY_IDX(
                    child->remaining_ranges, 0, svn_merge_range_t *);
                  *start = r1->start;
                  *end = r1->end;
                }
              else
                {
                  /* If CHILD->REMAINING_RANGES is null then LOCAL_ABSPATH
                     is inside an absent subtree in the merge target. */
                  *start = SVN_INVALID_REVNUM;
                  *end = SVN_INVALID_REVNUM;
                  break;
                }
            }
          else
            {
              /* We'e found another ancestor for LOCAL_ABSPATH.  Do its
                 first remaining range intersect with the previously
                 found ancestor? */
              svn_merge_range_t *r1 =
                APR_ARRAY_IDX(nearest_ancestor->remaining_ranges, 0,
                              svn_merge_range_t *);
              svn_merge_range_t *r2 =
                APR_ARRAY_IDX(child->remaining_ranges, 0,
                              svn_merge_range_t *);

              if (r1 && r2)
                {
                  svn_merge_range_t range1;
                  svn_merge_range_t range2;
                  svn_boolean_t reverse_merge = r1->start > r2->end;

                  /* Flip endpoints if this is a reverse merge. */
                  if (reverse_merge)
                    {
                      range1.start = r1->end;
                      range1.end = r1->start;
                      range2.start = r2->end;
                      range2.end = r2->start;
                    }
                  else
                    {
                      range1.start = r1->start;
                      range1.end = r1->end;
                      range2.start = r2->start;
                      range2.end = r2->end;
                    }

                  if (range1.start < range2.end && range2.start < range1.end)
                    {
                      *start = reverse_merge ?
                        MAX(r1->start, r2->start) : MIN(r1->start, r2->start);
                      *end = reverse_merge ?
                        MIN(r1->end, r2->end) : MAX(r1->end, r2->end);
                      nearest_ancestor = child;
                    }
                }
            }
        }
    }
  return nearest_ancestor;
}

/* Notify that we're starting to record mergeinfo for the merge of the
 * revision range RANGE into TARGET_ABSPATH.  RANGE should be null if the
 * merge sources are not from the same URL.
 *
 * This calls the client's notification receiver (as found in the client
 * context), with a WC abspath.
 */
static void
notify_mergeinfo_recording(const char *target_abspath,
                           const svn_merge_range_t *range,
                           svn_client_ctx_t *ctx,
                           apr_pool_t *pool)
{
  if (ctx->notify_func2)
    {
      svn_wc_notify_t *n = svn_wc_create_notify(
        target_abspath, svn_wc_notify_merge_record_info_begin, pool);

      n->merge_range = range ? svn_merge_range_dup(range, pool) : NULL;
      ctx->notify_func2(ctx->notify_baton2, n, pool);
    }
}

/* Notify that we're completing the merge into TARGET_ABSPATH.
 *
 * This calls the client's notification receiver (as found in the client
 * context), with a WC abspath.
 */
static void
notify_merge_completed(const char *target_abspath,

src/subversion/subversion/libsvn_client/merge.c  view on Meta::CPAN


  return SVN_NO_ERROR;
}

/* Set *OUT_RANGELIST to the intersection of IN_RANGELIST with the simple
 * (inheritable) revision range REV1:REV2, according to CONSIDER_INHERITANCE.
 * If REV1 is equal to REV2, the result is an empty rangelist, otherwise
 * REV1 must be less than REV2.
 *
 * Note: If CONSIDER_INHERITANCE is FALSE, the effect is to treat any non-
 * inheritable input ranges as if they were inheritable.  If it is TRUE, the
 * effect is to discard any non-inheritable input ranges.  Therefore the
 * ranges in *OUT_RANGELIST will always be inheritable. */
static svn_error_t *
rangelist_intersect_range(svn_rangelist_t **out_rangelist,
                          const svn_rangelist_t *in_rangelist,
                          svn_revnum_t rev1,
                          svn_revnum_t rev2,
                          svn_boolean_t consider_inheritance,
                          apr_pool_t *result_pool,
                          apr_pool_t *scratch_pool)
{
  SVN_ERR_ASSERT(rev1 <= rev2);

  if (rev1 < rev2)
    {
      svn_rangelist_t *simple_rangelist =
        svn_rangelist__initialize(rev1, rev2, TRUE, scratch_pool);

      SVN_ERR(svn_rangelist_intersect(out_rangelist,
                                      simple_rangelist, in_rangelist,
                                      consider_inheritance, result_pool));
    }
  else
    {
      *out_rangelist = apr_array_make(result_pool, 0,
                                      sizeof(svn_merge_range_t *));
    }
  return SVN_NO_ERROR;
}

/* Helper for fix_deleted_subtree_ranges().  Like fix_deleted_subtree_ranges()
   this function should only be called when honoring mergeinfo.

   CHILD, PARENT, REVISION1, REVISION2, and RA_SESSION are all cascaded from
   fix_deleted_subtree_ranges() -- see that function for more information on
   each.

   If PARENT is not the merge target then PARENT must have already have been
   processed by this function as a child.  Specifically, this means that
   PARENT->REMAINING_RANGES must already be populated -- it can be an empty
   rangelist but cannot be NULL.

   PRIMARY_URL is the merge source url of CHILD at the younger of REVISION1
   and REVISION2.

   Since this function is only invoked for subtrees of the merge target, the
   guarantees afforded by normalize_merge_sources() don't apply - see the
   'MERGEINFO MERGE SOURCE NORMALIZATION' comment at the top of this file.
   Therefore it is possible that PRIMARY_URL@REVISION1 and
   PRIMARY_URL@REVISION2 don't describe the endpoints of an unbroken line of
   history.  The purpose of this helper is to identify these cases of broken
   history and adjust CHILD->REMAINING_RANGES in such a way we don't later try
   to describe nonexistent path/revisions to the merge report editor -- see
   drive_merge_report_editor().

   If PRIMARY_URL@REVISION1 and PRIMARY_URL@REVISION2 describe an unbroken
   line of history then do nothing and leave CHILD->REMAINING_RANGES as-is.

   If neither PRIMARY_URL@REVISION1 nor PRIMARY_URL@REVISION2 exist then
   there is nothing to merge to CHILD->ABSPATH so set CHILD->REMAINING_RANGES
   equal to PARENT->REMAINING_RANGES.  This will cause the subtree to
   effectively ignore CHILD -- see 'Note: If the first svn_merge_range_t...'
   in drive_merge_report_editor()'s doc string.

   If PRIMARY_URL@REVISION1 *xor* PRIMARY_URL@REVISION2 exist then we take the
   subset of REVISION1:REVISION2 in CHILD->REMAINING_RANGES at which
   PRIMARY_URL doesn't exist and set that subset equal to
   PARENT->REMAINING_RANGES' intersection with that non-existent range.  Why?
   Because this causes CHILD->REMAINING_RANGES to be identical to
   PARENT->REMAINING_RANGES for revisions between REVISION1 and REVISION2 at
   which PRIMARY_URL doesn't exist.  As mentioned above this means that
   drive_merge_report_editor() won't attempt to describe these non-existent
   subtree path/ranges to the reporter (which would break the merge).

   If the preceding paragraph wasn't terribly clear then what follows spells
   out this function's behavior a bit more explicitly:

   For forward merges (REVISION1 < REVISION2)

     If PRIMARY_URL@REVISION1 exists but PRIMARY_URL@REVISION2 doesn't, then
     find the revision 'N' in which PRIMARY_URL@REVISION1 was deleted.  Leave
     the subset of CHILD->REMAINING_RANGES that intersects with
     REVISION1:(N - 1) as-is and set the subset of CHILD->REMAINING_RANGES
     that intersects with (N - 1):REVISION2 equal to PARENT->REMAINING_RANGES'
     intersection with (N - 1):REVISION2.

     If PRIMARY_URL@REVISION1 doesn't exist but PRIMARY_URL@REVISION2 does,
     then find the revision 'M' in which PRIMARY_URL@REVISION2 came into
     existence.  Leave the subset of CHILD->REMAINING_RANGES that intersects with
     (M - 1):REVISION2 as-is and set the subset of CHILD->REMAINING_RANGES
     that intersects with REVISION1:(M - 1) equal to PARENT->REMAINING_RANGES'
     intersection with REVISION1:(M - 1).

   For reverse merges (REVISION1 > REVISION2)

     If PRIMARY_URL@REVISION1 exists but PRIMARY_URL@REVISION2 doesn't, then
     find the revision 'N' in which PRIMARY_URL@REVISION1 came into existence.
     Leave the subset of CHILD->REMAINING_RANGES that intersects with
     REVISION2:(N - 1) as-is and set the subset of CHILD->REMAINING_RANGES
     that intersects with (N - 1):REVISION1 equal to PARENT->REMAINING_RANGES'
     intersection with (N - 1):REVISION1.

     If PRIMARY_URL@REVISION1 doesn't exist but PRIMARY_URL@REVISION2 does,
     then find the revision 'M' in which PRIMARY_URL@REVISION2 came into
     existence.  Leave the subset of CHILD->REMAINING_RANGES that intersects with
     REVISION2:(M - 1) as-is and set the subset of CHILD->REMAINING_RANGES
     that intersects with (M - 1):REVISION1 equal to PARENT->REMAINING_RANGES'
     intersection with REVISION1:(M - 1).

   SCRATCH_POOL is used for all temporary allocations.  Changes to CHILD are

src/subversion/subversion/libsvn_client/merge.c  view on Meta::CPAN

                                   real_source, remaining_range, result_pool);

              /* Only record partial mergeinfo if only a partial merge was
                 performed before a conflict was encountered. */
              range.end = r->end;
              break;
            }

          /* Now delete the just merged range from the hash
             (This list is used from notify_merge_begin)

            Directory merges use remove_first_range_from_remaining_ranges() */
          svn_sort__array_delete(ranges_to_merge, 0, 1);
        }
      merge_b->notify_begin.last_abspath = NULL;
    } /* !merge_b->record_only */

  /* Record updated WC mergeinfo to account for our new merges, minus
     any unresolved conflicts and skips.  We use the original
     REMAINING_RANGES here because we want to record all the requested
     merge ranges, include the noop ones.  */
  if (RECORD_MERGEINFO(merge_b) && remaining_ranges->nelts)
    {
      const char *mergeinfo_path = svn_client__pathrev_fspath(primary_src,
                                                              scratch_pool);
      svn_rangelist_t *filtered_rangelist;

      /* Filter any ranges from TARGET_WCPATH's own history, there is no
         need to record this explicitly in mergeinfo, it is already part
         of TARGET_WCPATH's natural history (implicit mergeinfo). */
      SVN_ERR(filter_natural_history_from_mergeinfo(
        &filtered_rangelist,
        mergeinfo_path,
        merge_target->implicit_mergeinfo,
        &range,
        iterpool));

      /* Only record mergeinfo if there is something other than
         self-referential mergeinfo, but don't record mergeinfo if
         TARGET_WCPATH was skipped. */
      if (filtered_rangelist->nelts
          && (apr_hash_count(merge_b->skipped_abspaths) == 0))
        {
          apr_hash_t *merges = apr_hash_make(iterpool);

          /* If merge target has inherited mergeinfo set it before
             recording the first merge range. */
          if (inherited)
            SVN_ERR(svn_client__record_wc_mergeinfo(target_abspath,
                                                    target_mergeinfo,
                                                    FALSE, ctx,
                                                    iterpool));

          svn_hash_sets(merges, target_abspath, filtered_rangelist);

          if (!squelch_mergeinfo_notifications)
            {
              /* Notify that we are recording mergeinfo describing a merge. */
              svn_merge_range_t n_range;

              SVN_ERR(svn_mergeinfo__get_range_endpoints(
                        &n_range.end, &n_range.start, merges, iterpool));
              n_range.inheritable = TRUE;
              notify_mergeinfo_recording(target_abspath, &n_range,
                                         merge_b->ctx, iterpool);
            }

          SVN_ERR(update_wc_mergeinfo(result_catalog, target_abspath,
                                      mergeinfo_path, merges, is_rollback,
                                      ctx, iterpool));
        }
    }

  merge_b->notify_begin.nodes_with_mergeinfo = NULL;

  svn_pool_destroy(iterpool);

  return SVN_NO_ERROR;
}

/* Helper for do_directory_merge() to handle the case where a merge editor
   drive adds explicit mergeinfo to a path which didn't have any explicit
   mergeinfo previously.

   MERGE_B is cascaded from the argument of the same
   name in do_directory_merge().  Should be called only after
   do_directory_merge() has called populate_remaining_ranges() and populated
   the remaining_ranges field of each child in
   CHILDREN_WITH_MERGEINFO (i.e. the remaining_ranges fields can be
   empty but never NULL).

   If MERGE_B->DRY_RUN is true do nothing, if it is false then
   for each path (if any) in MERGE_B->PATHS_WITH_NEW_MERGEINFO merge that
   path's inherited mergeinfo (if any) with its working explicit mergeinfo
   and set that as the path's new explicit mergeinfo.  Then add an
   svn_client__merge_path_t * element representing the path to
   CHILDREN_WITH_MERGEINFO if it isn't already present.  All fields
   in any elements added to CHILDREN_WITH_MERGEINFO are initialized
   to FALSE/NULL with the exception of 'path' and 'remaining_ranges'.  The
   latter is set to a rangelist equal to the remaining_ranges of the path's
   nearest path-wise ancestor in CHILDREN_WITH_MERGEINFO.

   Any elements added to CHILDREN_WITH_MERGEINFO are allocated
   in POOL. */
static svn_error_t *
process_children_with_new_mergeinfo(merge_cmd_baton_t *merge_b,
                                    apr_array_header_t *children_with_mergeinfo,
                                    apr_pool_t *pool)
{
  apr_pool_t *iterpool;
  apr_hash_index_t *hi;

  if (!merge_b->paths_with_new_mergeinfo || merge_b->dry_run)
    return SVN_NO_ERROR;

  /* Iterate over each path with explicit mergeinfo added by the merge. */
  iterpool = svn_pool_create(pool);
  for (hi = apr_hash_first(pool, merge_b->paths_with_new_mergeinfo);
       hi;
       hi = apr_hash_next(hi))
    {

src/subversion/subversion/libsvn_client/merge.c  view on Meta::CPAN

    {
      svn_revnum_t oldest_rev =
        (APR_ARRAY_IDX(potentially_unmerged_ranges,
                       0,
                       svn_merge_range_t *))->start + 1;
      svn_revnum_t youngest_rev =
        (APR_ARRAY_IDX(potentially_unmerged_ranges,
                       potentially_unmerged_ranges->nelts - 1,
                       svn_merge_range_t *))->end;
      log_find_operative_baton_t log_baton;
      const char *old_session_url;
      svn_error_t *err;

      log_baton.merged_catalog = merged_catalog;
      log_baton.unmerged_catalog = true_unmerged_catalog;
      log_baton.source_repos_rel_path
        = svn_client__pathrev_relpath(source_loc, scratch_pool);
      log_baton.target_fspath
        = svn_client__pathrev_fspath(target_loc, scratch_pool);
      log_baton.result_pool = result_pool;

      SVN_ERR(svn_client__ensure_ra_session_url(
                &old_session_url, ra_session, target_loc->url, scratch_pool));
      err = get_log(ra_session, "", youngest_rev, oldest_rev,
                    TRUE, /* discover_changed_paths */
                    log_find_operative_revs, &log_baton,
                    scratch_pool);
      SVN_ERR(svn_error_compose_create(
                err, svn_ra_reparent(ra_session, old_session_url, scratch_pool)));
    }

  return SVN_NO_ERROR;
}


/* Find the youngest revision that has been merged from target to source.
 *
 * If any location in TARGET_HISTORY_AS_MERGEINFO is mentioned in
 * SOURCE_MERGEINFO, then we know that at least one merge was done from the
 * target to the source.  In that case, set *YOUNGEST_MERGED_REV to the
 * youngest revision of that intersection (unless *YOUNGEST_MERGED_REV is
 * already younger than that).  Otherwise, leave *YOUNGEST_MERGED_REV alone.
 */
static svn_error_t *
find_youngest_merged_rev(svn_revnum_t *youngest_merged_rev,
                         svn_mergeinfo_t target_history_as_mergeinfo,
                         svn_mergeinfo_t source_mergeinfo,
                         apr_pool_t *scratch_pool)
{
  svn_mergeinfo_t explicit_source_target_history_intersection;

  SVN_ERR(svn_mergeinfo_intersect2(
            &explicit_source_target_history_intersection,
            source_mergeinfo, target_history_as_mergeinfo, TRUE,
            scratch_pool, scratch_pool));
  if (apr_hash_count(explicit_source_target_history_intersection))
    {
      svn_revnum_t old_rev, young_rev;

      /* Keep track of the youngest revision merged from target to source. */
      SVN_ERR(svn_mergeinfo__get_range_endpoints(
                &young_rev, &old_rev,
                explicit_source_target_history_intersection, scratch_pool));
      if (!SVN_IS_VALID_REVNUM(*youngest_merged_rev)
          || (young_rev > *youngest_merged_rev))
        *youngest_merged_rev = young_rev;
    }

  return SVN_NO_ERROR;
}

/* Set *FILTERED_MERGEINFO_P to the parts of TARGET_HISTORY_AS_MERGEINFO
 * that are not present in the source branch.
 *
 * SOURCE_MERGEINFO is the explicit or inherited mergeinfo of the source
 * branch SOURCE_PATHREV.  Extend SOURCE_MERGEINFO, modifying it in
 * place, to include the natural history (implicit mergeinfo) of
 * SOURCE_PATHREV.  ### But make these additions in SCRATCH_POOL.
 *
 * SOURCE_RA_SESSION is an RA session open to the repository containing
 * SOURCE_PATHREV; it may be temporarily reparented within this function.
 *
 * ### [JAF] This function is named '..._subroutine' simply because I
 *     factored it out based on code similarity, without knowing what it's
 *     purpose is.  We should clarify its purpose and choose a better name.
 */
static svn_error_t *
find_unmerged_mergeinfo_subroutine(svn_mergeinfo_t *filtered_mergeinfo_p,
                                   svn_mergeinfo_t target_history_as_mergeinfo,
                                   svn_mergeinfo_t source_mergeinfo,
                                   const svn_client__pathrev_t *source_pathrev,
                                   svn_ra_session_t *source_ra_session,
                                   svn_client_ctx_t *ctx,
                                   apr_pool_t *result_pool,
                                   apr_pool_t *scratch_pool)
{
  svn_mergeinfo_t source_history_as_mergeinfo;

  /* Get the source path's natural history and merge it into source
     path's explicit or inherited mergeinfo. */
  SVN_ERR(svn_client__get_history_as_mergeinfo(
            &source_history_as_mergeinfo, NULL /* has_rev_zero_history */,
            source_pathrev, source_pathrev->rev, SVN_INVALID_REVNUM,
            source_ra_session, ctx, scratch_pool));
  SVN_ERR(svn_mergeinfo_merge2(source_mergeinfo,
                               source_history_as_mergeinfo,
                               scratch_pool, scratch_pool));

  /* Now source_mergeinfo represents everything we know about
     source_path's history.  Now we need to know what part, if any, of the
     corresponding target's history is *not* part of source_path's total
     history; because it is neither shared history nor was it ever merged
     from the target to the source. */
  SVN_ERR(svn_mergeinfo_remove2(filtered_mergeinfo_p,
                                source_mergeinfo,
                                target_history_as_mergeinfo, TRUE,
                                result_pool, scratch_pool));
  return SVN_NO_ERROR;
}

/* Helper for calculate_left_hand_side() which produces a mergeinfo catalog

src/subversion/subversion/libsvn_client/merge.c  view on Meta::CPAN


  merge_target_t *target;
  svn_ra_session_t *target_ra_session;
  branch_history_t target_branch;

  /* Repos location of the youngest common ancestor of SOURCE and TARGET. */
  svn_client__pathrev_t *yca;
} source_and_target_t;

/* Set *INTERSECTION_P to the intersection of BRANCH_HISTORY with the
 * revision range OLDEST_REV to YOUNGEST_REV (inclusive).
 *
 * If the intersection is empty, the result will be a branch history object
 * containing an empty (not null) history.
 *
 * ### The 'tip' of the result is currently unchanged.
 */
static svn_error_t *
branch_history_intersect_range(branch_history_t **intersection_p,
                               const branch_history_t *branch_history,
                               svn_revnum_t oldest_rev,
                               svn_revnum_t youngest_rev,
                               apr_pool_t *result_pool,
                               apr_pool_t *scratch_pool)
{
  branch_history_t *result = apr_palloc(result_pool, sizeof(*result));

  SVN_ERR_ASSERT(SVN_IS_VALID_REVNUM(oldest_rev));
  SVN_ERR_ASSERT(SVN_IS_VALID_REVNUM(youngest_rev));
  SVN_ERR_ASSERT(oldest_rev >= 1);
  /* Allow a just-empty range (oldest = youngest + 1) but not an
   * arbitrary reverse range (such as oldest = youngest + 2). */
  SVN_ERR_ASSERT(oldest_rev <= youngest_rev + 1);

  if (oldest_rev <= youngest_rev)
    {
      SVN_ERR(svn_mergeinfo__filter_mergeinfo_by_ranges(
                &result->history, branch_history->history,
                youngest_rev, oldest_rev - 1, TRUE /* include_range */,
                result_pool, scratch_pool));
      result->history = svn_mergeinfo_dup(result->history, result_pool);
    }
  else
    {
      result->history = apr_hash_make(result_pool);
    }
  result->has_r0_history = FALSE;

  /* ### TODO: Set RESULT->tip to the tip of the intersection. */
  result->tip = svn_client__pathrev_dup(branch_history->tip, result_pool);

  *intersection_p = result;
  return SVN_NO_ERROR;
}

/* Set *OLDEST_P and *YOUNGEST_P to the oldest and youngest locations
 * (inclusive) along BRANCH.  OLDEST_P and/or YOUNGEST_P may be NULL if not
 * wanted.
 */
static svn_error_t *
branch_history_get_endpoints(svn_client__pathrev_t **oldest_p,
                             svn_client__pathrev_t **youngest_p,
                             const branch_history_t *branch,
                             apr_pool_t *result_pool,
                             apr_pool_t *scratch_pool)
{
  svn_revnum_t youngest_rev, oldest_rev;

  SVN_ERR(svn_mergeinfo__get_range_endpoints(
            &youngest_rev, &oldest_rev,
            branch->history, scratch_pool));
  if (oldest_p)
    *oldest_p = location_on_branch_at_rev(
                  branch, oldest_rev + 1, result_pool, scratch_pool);
  if (youngest_p)
    *youngest_p = location_on_branch_at_rev(
                    branch, youngest_rev, result_pool, scratch_pool);
  return SVN_NO_ERROR;
}

/* Implements the svn_log_entry_receiver_t interface.

  Set *BATON to LOG_ENTRY->revision and return SVN_ERR_CEASE_INVOCATION. */
static svn_error_t *
operative_rev_receiver(void *baton,
                       svn_log_entry_t *log_entry,
                       apr_pool_t *pool)
{
  svn_revnum_t *operative_rev = baton;

  *operative_rev = log_entry->revision;

  /* We've found the youngest merged or oldest eligible revision, so
     we're done...

     ...but wait, shouldn't we care if LOG_ENTRY->NON_INHERITABLE is
     true?  Because if it is, then LOG_ENTRY->REVISION is only
     partially merged/elgibile!  And our only caller,
     find_last_merged_location (via short_circuit_mergeinfo_log) is
     interested in *fully* merged revisions.  That's all true, but if
     find_last_merged_location() finds the youngest merged revision it
     will also check for the oldest eligible revision.  So in the case
     the youngest merged rev is non-inheritable, the *same* non-inheritable
     rev will be found as the oldest eligible rev -- and
     find_last_merged_location() handles that situation. */
  return svn_error_create(SVN_ERR_CEASE_INVOCATION, NULL, NULL);
}

/* Wrapper around svn_client__mergeinfo_log. All arguments are as per
   that private API.  The discover_changed_paths, depth, and revprops args to
   svn_client__mergeinfo_log are always TRUE, svn_depth_infinity_t,
   and empty array respectively.

   If RECEIVER raises a SVN_ERR_CEASE_INVOCATION error, but still sets
   *REVISION to a valid revnum, then clear the error.  Otherwise return
   any error. */
static svn_error_t*
short_circuit_mergeinfo_log(svn_mergeinfo_catalog_t *target_mergeinfo_cat,
                            svn_boolean_t finding_merged,
                            const char *target_path_or_url,
                            const svn_opt_revision_t *target_peg_revision,
                            const char *source_path_or_url,
                            const svn_opt_revision_t *source_peg_revision,
                            const svn_opt_revision_t *source_start_revision,
                            const svn_opt_revision_t *source_end_revision,
                            svn_log_entry_receiver_t receiver,
                            svn_revnum_t *revision,
                            svn_client_ctx_t *ctx,
                            svn_ra_session_t *ra_session,

src/subversion/subversion/libsvn_client/merge.c  view on Meta::CPAN

                                      source_branch->tip->url,
                                      &source_peg_rev,
                                      &source_end_rev, &source_start_rev,
                                      operative_rev_receiver,
                                      &youngest_merged_rev,
                                      ctx, ra_session,
                                      result_pool, scratch_pool));

  if (!SVN_IS_VALID_REVNUM(youngest_merged_rev))
    {
      /* No revisions have been completely merged from SOURCE_BRANCH to
         TARGET so the base for the next merge is the YCA. */
      *base_p = yca;
    }
  else
    {
      /* One or more revisions have already been completely merged from
         SOURCE_BRANCH to TARGET, now find the oldest revision, older
         than the youngest merged revision, which is still eligible to
         be merged, if such exists. */
      branch_history_t *contiguous_source;
      svn_revnum_t base_rev;
      svn_revnum_t oldest_eligible_rev = SVN_INVALID_REVNUM;

      /* If the only revisions eligible are younger than the youngest merged
         revision we can simply assume that the youngest eligible revision
         is the youngest merged revision.  Obviously this may not be true!
         The revisions between the youngest merged revision and the tip of
         the branch may have several inoperative revisions -- they may *all*
         be inoperative revisions!  But for the purpose of this function
         (i.e. finding the youngest revision after the YCA where all revs have
         been merged) that doesn't matter. */
      source_end_rev.value.number = youngest_merged_rev;
      SVN_ERR(short_circuit_mergeinfo_log(&target_mergeinfo_cat,
                                          FALSE, /* Find eligible */
                                          target->url, &target_opt_rev,
                                          source_branch->tip->url,
                                          &source_peg_rev,
                                          &source_start_rev, &source_end_rev,
                                          operative_rev_receiver,
                                          &oldest_eligible_rev,
                                          ctx, ra_session,
                                          scratch_pool, scratch_pool));

      /* If there are revisions eligible for merging, use the oldest one
         to calculate the base.  Otherwise there are no operative revisions
         to merge and we can simple set the base to the youngest revision
         already merged. */
      if (SVN_IS_VALID_REVNUM(oldest_eligible_rev))
        base_rev = oldest_eligible_rev - 1;
      else
        base_rev = youngest_merged_rev;

      /* Find the branch location just before the oldest eligible rev.
         (We can't just use the base revs calculated above because the branch
         might have a gap there.) */
      SVN_ERR(branch_history_intersect_range(&contiguous_source,
                                             source_branch, yca->rev,
                                             base_rev,
                                             scratch_pool, scratch_pool));
      SVN_ERR(branch_history_get_endpoints(NULL, base_p, contiguous_source,
                                           result_pool, scratch_pool));
    }

  return SVN_NO_ERROR;
}

/* Find a merge base location on the target branch, like in a sync
 * merge.
 *
 *                BASE          S_T->source
 *          o-------o-----------o---
 *         /         \           \
 *   -----o     prev. \           \  this
 *     YCA \    merge  \           \ merge
 *          o-----------o-----------o
 *                                  S_T->target
 *
 * Set *BASE_P to BASE, the youngest location in the history of S_T->source
 * (at or after the YCA) at which all revisions up to BASE are effectively
 * merged into S_T->target.
 *
 * If no locations on the history of S_T->source are effectively merged to
 * S_T->target, set *BASE_P to the YCA.
 */
static svn_error_t *
find_base_on_source(svn_client__pathrev_t **base_p,
                    source_and_target_t *s_t,
                    svn_client_ctx_t *ctx,
                    apr_pool_t *result_pool,
                    apr_pool_t *scratch_pool)
{
  SVN_ERR(find_last_merged_location(base_p,
                                    s_t->yca,
                                    &s_t->source_branch,
                                    s_t->target_branch.tip,
                                    ctx,
                                    s_t->source_ra_session,
                                    result_pool, scratch_pool));
  return SVN_NO_ERROR;
}

/* Find a merge base location on the target branch, like in a reintegrate
 * merge.
 *
 *                              S_T->source
 *          o-----------o-------o---
 *         /    prev.  /         \
 *   -----o     merge /           \  this
 *     YCA \         /             \ merge
 *          o-------o---------------o
 *                BASE              S_T->target
 *
 * Set *BASE_P to BASE, the youngest location in the history of S_T->target
 * (at or after the YCA) at which all revisions up to BASE are effectively
 * merged into S_T->source.
 *
 * If no locations on the history of S_T->target are effectively merged to
 * S_T->source, set *BASE_P to the YCA.
 */
static svn_error_t *



( run in 1.112 second using v1.01-cache-2.11-cpan-524268b4103 )