diff options
Diffstat (limited to 'subversion/libsvn_client/diff.c')
-rw-r--r-- | subversion/libsvn_client/diff.c | 891 |
1 files changed, 541 insertions, 350 deletions
diff --git a/subversion/libsvn_client/diff.c b/subversion/libsvn_client/diff.c index ba6e91e..30d00b0 100644 --- a/subversion/libsvn_client/diff.c +++ b/subversion/libsvn_client/diff.c @@ -23,6 +23,9 @@ /* ==================================================================== */ +/* We define this here to remove any further warnings about the usage of + experimental functions in this file. */ +#define SVN_EXPERIMENTAL /*** Includes. ***/ @@ -66,6 +69,31 @@ _("Path '%s' must be an immediate child of " \ "the directory '%s'"), path, relative_to_dir) +/* State provided by the diff drivers; used by the diff writer */ +typedef struct diff_driver_info_t +{ + /* The anchor to prefix before wc paths */ + const char *anchor; + + /* Relative path of ra session from repos_root_url. + + Used only in printing git diff headers. The repository-root-relative + path of ... ### what user-visible property of the diff? */ + const char *session_relpath; + + /* Used only in printing git diff headers. Used to find the + repository-root-relative path of a WC path. */ + svn_wc_context_t *wc_ctx; + + /* The original targets passed to the diff command. We may need + these to construct distinctive diff labels when comparing the + same relative path in the same revision, under different anchors + (for example, when comparing a trunk against a branch). */ + const char *orig_path_1; + const char *orig_path_2; +} diff_driver_info_t; + + /* Calculate the repository relative path of DIFF_RELPATH, using * SESSION_RELPATH and WC_CTX, and return the result in *REPOS_RELPATH. * ORIG_TARGET is the related original target passed to the diff command, @@ -120,25 +148,47 @@ make_repos_relpath(const char **repos_relpath, return SVN_NO_ERROR; } -/* Adjust *INDEX_PATH, *ORIG_PATH_1 and *ORIG_PATH_2, representing the changed - * node and the two original targets passed to the diff command, to handle the - * case when we're dealing with different anchors. RELATIVE_TO_DIR is the - * directory the diff target should be considered relative to. - * ANCHOR is the local path where the diff editor is anchored. The resulting - * values are allocated in RESULT_POOL and temporary allocations are performed - * in SCRATCH_POOL. */ +/* Adjust paths to handle the case when we're dealing with different anchors. + * + * Set *INDEX_PATH to the new relative path. Set *LABEL_PATH1 and + * *LABEL_PATH2 to that path annotated with the unique parts of ORIG_PATH_1 + * and ORIG_PATH_2 respectively, like this: + * + * INDEX_PATH: "path" + * LABEL_PATH1: "path\t(.../branches/branch1)" + * LABEL_PATH2: "path\t(.../trunk)" + * + * Make the output paths relative to RELATIVE_TO_DIR (if not null) by + * removing it from the beginning of (ANCHOR + RELPATH). + * + * ANCHOR (if not null) is the local path where the diff editor is anchored. + * RELPATH is the path to the changed node within the diff editor, so + * relative to ANCHOR. + * + * RELATIVE_TO_DIR and ANCHOR are of the same form -- either absolute local + * paths or relative paths relative to the same base. + * + * ORIG_PATH_1 and ORIG_PATH_2 represent the two original target paths or + * URLs passed to the diff command. + * + * Allocate results in RESULT_POOL (or as a pointer to RELPATH) and + * temporary data in SCRATCH_POOL. + */ static svn_error_t * adjust_paths_for_diff_labels(const char **index_path, - const char **orig_path_1, - const char **orig_path_2, + const char **label_path1, + const char **label_path2, const char *relative_to_dir, const char *anchor, + const char *relpath, + const char *orig_path_1, + const char *orig_path_2, apr_pool_t *result_pool, apr_pool_t *scratch_pool) { - const char *new_path = *index_path; - const char *new_path1 = *orig_path_1; - const char *new_path2 = *orig_path_2; + const char *new_path = relpath; + const char *new_path1 = orig_path_1; + const char *new_path2 = orig_path_2; if (anchor) new_path = svn_dirent_join(anchor, new_path, result_pool); @@ -177,6 +227,7 @@ adjust_paths_for_diff_labels(const char **index_path, /* ### BH: We can now just construct the repos_relpath, etc. as the anchor is available. See also make_repos_relpath() */ + /* Remove the common prefix of NEW_PATH1 and NEW_PATH2. */ is_url1 = svn_path_is_url(new_path1); is_url2 = svn_path_is_url(new_path2); @@ -220,8 +271,8 @@ adjust_paths_for_diff_labels(const char **index_path, new_path2 = apr_psprintf(result_pool, "%s\t(.../%s)", new_path, new_path2); *index_path = new_path; - *orig_path_1 = new_path1; - *orig_path_2 = new_path2; + *label_path1 = new_path1; + *label_path2 = new_path2; return SVN_NO_ERROR; } @@ -383,28 +434,33 @@ maybe_print_mode_change(svn_stream_t *os, } /* Print a git diff header showing the OPERATION to the stream OS using - * HEADER_ENCODING. Return suitable diff labels for the git diff in *LABEL1 - * and *LABEL2. REPOS_RELPATH1 and REPOS_RELPATH2 are relative to reposroot. - * are the paths passed to the original diff command. REV1 and REV2 are - * revisions being diffed. COPYFROM_PATH and COPYFROM_REV indicate where the + * HEADER_ENCODING. + * + * Return suitable diff labels for the git diff in *LABEL1 and *LABEL2. + * + * REV1 and REV2 are the revisions being diffed. + * COPYFROM_PATH and COPYFROM_REV indicate where the * diffed item was copied from. * Use SCRATCH_POOL for temporary allocations. */ static svn_error_t * print_git_diff_header(svn_stream_t *os, const char **label1, const char **label2, svn_diff_operation_kind_t operation, - const char *repos_relpath1, - const char *repos_relpath2, svn_revnum_t rev1, svn_revnum_t rev2, + const char *diff_relpath, const char *copyfrom_path, svn_revnum_t copyfrom_rev, apr_hash_t *left_props, apr_hash_t *right_props, const char *git_index_shas, const char *header_encoding, + const diff_driver_info_t *ddi, apr_pool_t *scratch_pool) { + const char *repos_relpath1; + const char *repos_relpath2; + const char *copyfrom_repos_relpath = NULL; svn_boolean_t exec_bit1 = (svn_prop_get_value(left_props, SVN_PROP_EXECUTABLE) != NULL); svn_boolean_t exec_bit2 = (svn_prop_get_value(right_props, @@ -414,6 +470,26 @@ print_git_diff_header(svn_stream_t *os, svn_boolean_t symlink_bit2 = (svn_prop_get_value(right_props, SVN_PROP_SPECIAL) != NULL); + SVN_ERR(make_repos_relpath(&repos_relpath1, diff_relpath, + ddi->orig_path_1, + ddi->session_relpath, + ddi->wc_ctx, + ddi->anchor, + scratch_pool, scratch_pool)); + SVN_ERR(make_repos_relpath(&repos_relpath2, diff_relpath, + ddi->orig_path_2, + ddi->session_relpath, + ddi->wc_ctx, + ddi->anchor, + scratch_pool, scratch_pool)); + if (copyfrom_path) + SVN_ERR(make_repos_relpath(©from_repos_relpath, copyfrom_path, + ddi->orig_path_2, + ddi->session_relpath, + ddi->wc_ctx, + ddi->anchor, + scratch_pool, scratch_pool)); + if (operation == svn_diff_op_deleted) { SVN_ERR(print_git_diff_header_deleted(os, header_encoding, @@ -487,26 +563,45 @@ print_git_diff_header(svn_stream_t *os, return SVN_NO_ERROR; } +/* Print the "Index:" and "=====" lines. + * Show the paths in platform-independent format ('/' separators) + */ +static svn_error_t * +print_diff_index_header(svn_stream_t *outstream, + const char *header_encoding, + const char *index_path, + const char *suffix, + apr_pool_t *scratch_pool) +{ + SVN_ERR(svn_stream_printf_from_utf8(outstream, + header_encoding, scratch_pool, + "Index: %s%s" APR_EOL_STR + SVN_DIFF__EQUAL_STRING APR_EOL_STR, + index_path, suffix)); + return SVN_NO_ERROR; +} + /* A helper func that writes out verbal descriptions of property diffs to OUTSTREAM. Of course, OUTSTREAM will probably be whatever was - passed to svn_client_diff6(), which is probably stdout. + passed to svn_client_diff7(), which is probably stdout. ### FIXME needs proper docstring If USE_GIT_DIFF_FORMAT is TRUE, pring git diff headers, which always - show paths relative to the repository root. RA_SESSION and WC_CTX are - needed to normalize paths relative the repository root, and are ignored - if USE_GIT_DIFF_FORMAT is FALSE. - - ANCHOR is the local path where the diff editor is anchored. */ + show paths relative to the repository root. DDI->session_relpath and + DDI->wc_ctx are needed to normalize paths relative the repository root, + and are ignored if USE_GIT_DIFF_FORMAT is FALSE. + + If @a pretty_print_mergeinfo is true, then describe 'svn:mergeinfo' + property changes in a human-readable form that says what changes were + merged or reverse merged; otherwise (or if the mergeinfo property values + don't parse correctly) display them just like any other property. + */ static svn_error_t * display_prop_diffs(const apr_array_header_t *propchanges, apr_hash_t *left_props, apr_hash_t *right_props, const char *diff_relpath, - const char *anchor, - const char *orig_path1, - const char *orig_path2, svn_revnum_t rev1, svn_revnum_t rev2, const char *encoding, @@ -514,32 +609,29 @@ display_prop_diffs(const apr_array_header_t *propchanges, const char *relative_to_dir, svn_boolean_t show_diff_header, svn_boolean_t use_git_diff_format, - const char *ra_session_relpath, + svn_boolean_t pretty_print_mergeinfo, + const diff_driver_info_t *ddi, svn_cancel_func_t cancel_func, void *cancel_baton, - svn_wc_context_t *wc_ctx, apr_pool_t *scratch_pool) { const char *repos_relpath1 = NULL; - const char *repos_relpath2 = NULL; - const char *index_path = diff_relpath; - const char *adjusted_path1 = orig_path1; - const char *adjusted_path2 = orig_path2; + const char *index_path; + const char *label_path1, *label_path2; if (use_git_diff_format) { - SVN_ERR(make_repos_relpath(&repos_relpath1, diff_relpath, orig_path1, - ra_session_relpath, wc_ctx, anchor, - scratch_pool, scratch_pool)); - SVN_ERR(make_repos_relpath(&repos_relpath2, diff_relpath, orig_path2, - ra_session_relpath, wc_ctx, anchor, + SVN_ERR(make_repos_relpath(&repos_relpath1, diff_relpath, ddi->orig_path_1, + ddi->session_relpath, ddi->wc_ctx, ddi->anchor, scratch_pool, scratch_pool)); } /* If we're creating a diff on the wc root, path would be empty. */ - SVN_ERR(adjust_paths_for_diff_labels(&index_path, &adjusted_path1, - &adjusted_path2, - relative_to_dir, anchor, + SVN_ERR(adjust_paths_for_diff_labels(&index_path, + &label_path1, &label_path2, + relative_to_dir, ddi->anchor, + diff_relpath, + ddi->orig_path_1, ddi->orig_path_2, scratch_pool, scratch_pool)); if (show_diff_header) @@ -547,27 +639,21 @@ display_prop_diffs(const apr_array_header_t *propchanges, const char *label1; const char *label2; - label1 = diff_label(adjusted_path1, rev1, scratch_pool); - label2 = diff_label(adjusted_path2, rev2, scratch_pool); - - /* ### Should we show the paths in platform specific format, - * ### diff_content_changed() does not! */ + label1 = diff_label(label_path1, rev1, scratch_pool); + label2 = diff_label(label_path2, rev2, scratch_pool); - SVN_ERR(svn_stream_printf_from_utf8(outstream, encoding, scratch_pool, - "Index: %s" APR_EOL_STR - SVN_DIFF__EQUAL_STRING APR_EOL_STR, - index_path)); + SVN_ERR(print_diff_index_header(outstream, encoding, + index_path, "", scratch_pool)); if (use_git_diff_format) SVN_ERR(print_git_diff_header(outstream, &label1, &label2, svn_diff_op_modified, - repos_relpath1, repos_relpath2, - rev1, rev2, NULL, - SVN_INVALID_REVNUM, - left_props, - right_props, + rev1, rev2, + diff_relpath, + NULL, SVN_INVALID_REVNUM, + left_props, right_props, NULL, - encoding, scratch_pool)); + encoding, ddi, scratch_pool)); /* --- label1 * +++ label2 */ @@ -588,7 +674,7 @@ display_prop_diffs(const apr_array_header_t *propchanges, SVN_ERR(svn_diff__display_prop_diffs( outstream, encoding, propchanges, left_props, - TRUE /* pretty_print_mergeinfo */, + pretty_print_mergeinfo, -1 /* context_size */, cancel_func, cancel_baton, scratch_pool)); @@ -599,24 +685,6 @@ display_prop_diffs(const apr_array_header_t *propchanges, /*** Callbacks for 'svn diff', invoked by the repos-diff editor. ***/ -/* State provided by the diff drivers; used by the diff writer */ -typedef struct diff_driver_info_t -{ - /* The anchor to prefix before wc paths */ - const char *anchor; - - /* Relative path of ra session from repos_root_url */ - const char *session_relpath; - - /* The original targets passed to the diff command. We may need - these to construct distinctive diff labels when comparing the - same relative path in the same revision, under different anchors - (for example, when comparing a trunk against a branch). */ - const char *orig_path_1; - const char *orig_path_2; -} diff_driver_info_t; - - /* Diff writer state */ typedef struct diff_writer_info_t { @@ -668,11 +736,12 @@ typedef struct diff_writer_info_t /* Whether to ignore copyfrom information when showing adds */ svn_boolean_t show_copies_as_adds; + /* Whether to show mergeinfo prop changes in human-readable form */ + svn_boolean_t pretty_print_mergeinfo; + /* Empty files for creating diffs or NULL if not used yet */ const char *empty_file; - svn_wc_context_t *wc_ctx; - svn_cancel_func_t cancel_func; void *cancel_baton; @@ -708,9 +777,6 @@ diff_props_changed(const char *diff_relpath, * dir_props_changed(). */ SVN_ERR(display_prop_diffs(props, left_props, right_props, diff_relpath, - dwi->ddi.anchor, - dwi->ddi.orig_path_1, - dwi->ddi.orig_path_2, rev1, rev2, dwi->header_encoding, @@ -718,10 +784,10 @@ diff_props_changed(const char *diff_relpath, dwi->relative_to_dir, show_diff_header, dwi->use_git_diff_format, - dwi->ddi.session_relpath, + dwi->pretty_print_mergeinfo, + &dwi->ddi, dwi->cancel_func, dwi->cancel_baton, - dwi->wc_ctx, scratch_pool)); } @@ -785,9 +851,12 @@ transform_link_to_git(const char **new_tmpfile, } /* Show differences between TMPFILE1 and TMPFILE2. DIFF_RELPATH, REV1, and - REV2 are used in the headers to indicate the file and revisions. If either - MIMETYPE1 or MIMETYPE2 indicate binary content, don't show a diff, - but instead print a warning message. + REV2 are used in the headers to indicate the file and revisions. + + If either side has an svn:mime-type property that indicates 'binary' + content, then if DWI->force_binary is set, attempt to produce the + diff in the usual way, otherwise produce a 'GIT binary diff' in git mode + or print a warning message in non-git mode. If FORCE_DIFF is TRUE, always write a diff, even for empty diffs. @@ -812,9 +881,8 @@ diff_content_changed(svn_boolean_t *wrote_header, svn_stream_t *outstream = dwi->outstream; const char *label1, *label2; svn_boolean_t mt1_binary = FALSE, mt2_binary = FALSE; - const char *index_path = diff_relpath; - const char *path1 = dwi->ddi.orig_path_1; - const char *path2 = dwi->ddi.orig_path_2; + const char *index_path; + const char *label_path1, *label_path2; const char *mimetype1 = svn_prop_get_value(left_props, SVN_PROP_MIME_TYPE); const char *mimetype2 = svn_prop_get_value(right_props, SVN_PROP_MIME_TYPE); const char *index_shas = NULL; @@ -824,12 +892,15 @@ diff_content_changed(svn_boolean_t *wrote_header, return SVN_NO_ERROR; /* Generate the diff headers. */ - SVN_ERR(adjust_paths_for_diff_labels(&index_path, &path1, &path2, + SVN_ERR(adjust_paths_for_diff_labels(&index_path, + &label_path1, &label_path2, rel_to_dir, dwi->ddi.anchor, + diff_relpath, + dwi->ddi.orig_path_1, dwi->ddi.orig_path_2, scratch_pool, scratch_pool)); - label1 = diff_label(path1, rev1, scratch_pool); - label2 = diff_label(path2, rev2, scratch_pool); + label1 = diff_label(label_path1, rev1, scratch_pool); + label2 = diff_label(label_path2, rev2, scratch_pool); /* Possible easy-out: if either mime-type is binary and force was not specified, don't attempt to generate a viewable diff at all. @@ -869,12 +940,8 @@ diff_content_changed(svn_boolean_t *wrote_header, if (! dwi->force_binary && (mt1_binary || mt2_binary)) { /* Print out the diff header. */ - SVN_ERR(svn_stream_printf_from_utf8(outstream, - dwi->header_encoding, scratch_pool, - "Index: %s" APR_EOL_STR - SVN_DIFF__EQUAL_STRING APR_EOL_STR, - index_path)); - + SVN_ERR(print_diff_index_header(outstream, dwi->header_encoding, + index_path, "", scratch_pool)); *wrote_header = TRUE; /* ### Print git diff headers. */ @@ -883,40 +950,17 @@ diff_content_changed(svn_boolean_t *wrote_header, { svn_stream_t *left_stream; svn_stream_t *right_stream; - const char *repos_relpath1; - const char *repos_relpath2; - const char *copyfrom_repos_relpath = NULL; - - SVN_ERR(make_repos_relpath(&repos_relpath1, diff_relpath, - dwi->ddi.orig_path_1, - dwi->ddi.session_relpath, - dwi->wc_ctx, - dwi->ddi.anchor, - scratch_pool, scratch_pool)); - SVN_ERR(make_repos_relpath(&repos_relpath2, diff_relpath, - dwi->ddi.orig_path_2, - dwi->ddi.session_relpath, - dwi->wc_ctx, - dwi->ddi.anchor, - scratch_pool, scratch_pool)); - if (copyfrom_path) - SVN_ERR(make_repos_relpath(©from_repos_relpath, copyfrom_path, - dwi->ddi.orig_path_2, - dwi->ddi.session_relpath, - dwi->wc_ctx, - dwi->ddi.anchor, - scratch_pool, scratch_pool)); - SVN_ERR(print_git_diff_header(outstream, &label1, &label2, + + SVN_ERR(print_git_diff_header(outstream, + &label1, &label2, operation, - repos_relpath1, repos_relpath2, rev1, rev2, - copyfrom_repos_relpath, - copyfrom_rev, - left_props, - right_props, + diff_relpath, + copyfrom_path, copyfrom_rev, + left_props, right_props, index_shas, dwi->header_encoding, - scratch_pool)); + &dwi->ddi, scratch_pool)); SVN_ERR(svn_stream_open_readonly(&left_stream, tmpfile1, scratch_pool, scratch_pool)); @@ -973,11 +1017,9 @@ diff_content_changed(svn_boolean_t *wrote_header, int exitcode; /* Print out the diff header. */ - SVN_ERR(svn_stream_printf_from_utf8(outstream, - dwi->header_encoding, scratch_pool, - "Index: %s" APR_EOL_STR - SVN_DIFF__EQUAL_STRING APR_EOL_STR, - index_path)); + SVN_ERR(print_diff_index_header(outstream, dwi->header_encoding, + index_path, "", scratch_pool)); + *wrote_header = TRUE; /* ### Do we want to add git diff headers here too? I'd say no. The * ### 'Index' and '===' line is something subversion has added. The rest @@ -1030,10 +1072,6 @@ diff_content_changed(svn_boolean_t *wrote_header, scratch_pool), NULL, NULL, scratch_pool)); } - - /* If we have printed a diff for this path, mark it as visited. */ - if (exitcode == 1) - *wrote_header = TRUE; } else /* use libsvn_diff to generate the diff */ { @@ -1048,49 +1086,22 @@ diff_content_changed(svn_boolean_t *wrote_header, || svn_diff_contains_diffs(diff)) { /* Print out the diff header. */ - SVN_ERR(svn_stream_printf_from_utf8(outstream, - dwi->header_encoding, scratch_pool, - "Index: %s" APR_EOL_STR - SVN_DIFF__EQUAL_STRING APR_EOL_STR, - index_path)); + SVN_ERR(print_diff_index_header(outstream, dwi->header_encoding, + index_path, "", scratch_pool)); + *wrote_header = TRUE; if (dwi->use_git_diff_format) { - const char *repos_relpath1; - const char *repos_relpath2; - const char *copyfrom_repos_relpath = NULL; - - SVN_ERR(make_repos_relpath(&repos_relpath1, diff_relpath, - dwi->ddi.orig_path_1, - dwi->ddi.session_relpath, - dwi->wc_ctx, - dwi->ddi.anchor, - scratch_pool, scratch_pool)); - SVN_ERR(make_repos_relpath(&repos_relpath2, diff_relpath, - dwi->ddi.orig_path_2, - dwi->ddi.session_relpath, - dwi->wc_ctx, - dwi->ddi.anchor, - scratch_pool, scratch_pool)); - if (copyfrom_path) - SVN_ERR(make_repos_relpath(©from_repos_relpath, - copyfrom_path, - dwi->ddi.orig_path_2, - dwi->ddi.session_relpath, - dwi->wc_ctx, - dwi->ddi.anchor, - scratch_pool, scratch_pool)); - SVN_ERR(print_git_diff_header(outstream, &label1, &label2, + SVN_ERR(print_git_diff_header(outstream, + &label1, &label2, operation, - repos_relpath1, repos_relpath2, rev1, rev2, - copyfrom_repos_relpath, - copyfrom_rev, - left_props, - right_props, + diff_relpath, + copyfrom_path, copyfrom_rev, + left_props, right_props, index_shas, dwi->header_encoding, - scratch_pool)); + &dwi->ddi, scratch_pool)); } /* Output the actual diff */ @@ -1102,10 +1113,6 @@ diff_content_changed(svn_boolean_t *wrote_header, dwi->options.for_internal->context_size, dwi->cancel_func, dwi->cancel_baton, scratch_pool)); - - /* If we have printed a diff for this path, mark it as visited. */ - if (dwi->use_git_diff_format || svn_diff_contains_diffs(diff)) - *wrote_header = TRUE; } } @@ -1180,11 +1187,9 @@ diff_file_added(const char *relpath, index_path = svn_dirent_join(dwi->ddi.anchor, relpath, scratch_pool); - SVN_ERR(svn_stream_printf_from_utf8(dwi->outstream, - dwi->header_encoding, scratch_pool, - "Index: %s (added)" APR_EOL_STR - SVN_DIFF__EQUAL_STRING APR_EOL_STR, - index_path)); + SVN_ERR(print_diff_index_header(dwi->outstream, dwi->header_encoding, + index_path, " (added)", + scratch_pool)); wrote_header = TRUE; return SVN_NO_ERROR; } @@ -1270,11 +1275,9 @@ diff_file_deleted(const char *relpath, index_path = svn_dirent_join(dwi->ddi.anchor, relpath, scratch_pool); - SVN_ERR(svn_stream_printf_from_utf8(dwi->outstream, - dwi->header_encoding, scratch_pool, - "Index: %s (deleted)" APR_EOL_STR - SVN_DIFF__EQUAL_STRING APR_EOL_STR, - index_path)); + SVN_ERR(print_diff_index_header(dwi->outstream, dwi->header_encoding, + index_path, " (deleted)", + scratch_pool)); } else { @@ -1537,11 +1540,22 @@ check_diff_target_exists(const char *url, /** Prepare a repos repos diff between PATH_OR_URL1 and * PATH_OR_URL2@PEG_REVISION, in the revision range REVISION1:REVISION2. - * Return URLs and peg revisions in *URL1, *REV1 and in *URL2, *REV2. - * Return suitable anchors in *ANCHOR1 and *ANCHOR2, and targets in - * *TARGET1 and *TARGET2, based on *URL1 and *URL2. - * Indicate the corresponding node kinds in *KIND1 and *KIND2, and verify + * + * Return the resolved URL and peg revision pairs in *URL1, *REV1 and in + * *URL2, *REV2. + * + * Return suitable anchor URL and target pairs in *ANCHOR1, *TARGET1 and + * in *ANCHOR2, *TARGET2, corresponding to *URL1 and *URL2. + * + * (The choice of anchor URLs here appears to be: start with *URL1, *URL2; + * then take the parent dir on both sides, unless either of *URL1 or *URL2 + * is the repository root or the parent dir of *URL1 is unreadable.) + * + * Set *KIND1 and *KIND2 to the node kinds of *URL1 and *URL2, and verify * that at least one of the diff targets exists. + * + * Set *RA_SESSION to an RA session parented at the URL *ANCHOR1. + * * Use client context CTX. Do all allocations in POOL. */ static svn_error_t * diff_prepare_repos_repos(const char **url1, @@ -1766,8 +1780,8 @@ diff_prepare_repos_repos(const char **url1, /* A Theoretical Note From Ben, regarding do_diff(). - This function is really svn_client_diff6(). If you read the public - API description for svn_client_diff6(), it sounds quite Grand. It + This function is really svn_client_diff7(). If you read the public + API description for svn_client_diff7(), it sounds quite Grand. It sounds really generalized and abstract and beautiful: that it will diff any two paths, be they working-copy paths or URLs, at any two revisions. @@ -1791,7 +1805,7 @@ diff_prepare_repos_repos(const char **url1, pigeonholed into one of these use-cases, we currently bail with a friendly apology. - Perhaps someday a brave soul will truly make svn_client_diff6() + Perhaps someday a brave soul will truly make svn_client_diff7() perfectly general. For now, we live with the 90% case. Certainly, the commandline client only calls this function in legal ways. When there are other users of svn_client.h, maybe this will become @@ -1804,7 +1818,7 @@ static svn_error_t * unsupported_diff_error(svn_error_t *child_err) { return svn_error_create(SVN_ERR_INCORRECT_PARAMS, child_err, - _("Sorry, svn_client_diff6 was called in a way " + _("Sorry, svn_client_diff7 was called in a way " "that is not yet supported")); } @@ -1813,12 +1827,14 @@ unsupported_diff_error(svn_error_t *child_err) PATH1 and PATH2 are both working copy paths. REVISION1 and REVISION2 are their respective revisions. - All other options are the same as those passed to svn_client_diff6(). */ + For now, require PATH1=PATH2, REVISION1='base', REVISION2='working', + otherwise return an error. + + Anchor DIFF_PROCESSOR at the requested diff targets. + + All other options are the same as those passed to svn_client_diff7(). */ static svn_error_t * -diff_wc_wc(const char **root_relpath, - svn_boolean_t *root_is_dir, - struct diff_driver_info_t *ddi, - const char *path1, +diff_wc_wc(const char *path1, const svn_opt_revision_t *revision1, const char *path2, const svn_opt_revision_t *revision2, @@ -1844,24 +1860,12 @@ diff_wc_wc(const char **root_relpath, && (revision2->kind == svn_opt_revision_working)))) return unsupported_diff_error( svn_error_create(SVN_ERR_INCORRECT_PARAMS, NULL, - _("Only diffs between a path's text-base " - "and its working files are supported at this time" + _("A non-URL diff at this time must be either from " + "a path's base to the same path's working version " + "or between the working versions of two paths" ))); - if (ddi) - { - svn_node_kind_t kind; - - SVN_ERR(svn_wc_read_kind2(&kind, ctx->wc_ctx, abspath1, - TRUE, FALSE, scratch_pool)); - - if (kind != svn_node_dir) - ddi->anchor = svn_dirent_dirname(path1, scratch_pool); - else - ddi->anchor = path1; - } - - SVN_ERR(svn_wc__diff7(root_relpath, root_is_dir, + SVN_ERR(svn_wc__diff7(TRUE, ctx->wc_ctx, abspath1, depth, ignore_ancestry, changelists, diff_processor, @@ -1878,11 +1882,31 @@ diff_wc_wc(const char **root_relpath, and the actual two paths compared are determined by following copy history from PATH_OR_URL2. - All other options are the same as those passed to svn_client_diff6(). */ + If DDI is null, anchor the DIFF_PROCESSOR at the requested diff + targets. (This case is used by diff-summarize.) + + If DDI is non-null: Set DDI->orig_path_* to the two diff target URLs as + resolved at the given revisions; set DDI->anchor to an anchor WC path + if either of PATH_OR_URL* is given as a WC path, else to null; set + DDI->session_relpath to the repository-relpath of the anchor URL for + DDI->orig_path_1. Anchor the DIFF_PROCESSOR at the anchor chosen + for the underlying diff implementation if the target on either side + is a file, else at the actual requested targets. + + (The choice of WC anchor implementated here for DDI->anchor appears to + be: choose PATH_OR_URL2 (if it's a WC path) or else PATH_OR_URL1 (if + it's a WC path); then take its parent dir unless both resolved URLs + refer to directories.) + + (For the choice of URL anchor for DDI->session_relpath, see + diff_prepare_repos_repos().) + + ### Bizarre anchoring. TODO: always anchor DIFF_PROCESSOR at the + requested targets. + + All other options are the same as those passed to svn_client_diff7(). */ static svn_error_t * -diff_repos_repos(const char **root_relpath, - svn_boolean_t *root_is_dir, - struct diff_driver_info_t *ddi, +diff_repos_repos(struct diff_driver_info_t *ddi, const char *path_or_url1, const char *path_or_url2, const svn_opt_revision_t *revision1, @@ -1974,14 +1998,16 @@ diff_repos_repos(const char **root_relpath, target1 = str_tmp; diff_processor = svn_diff__tree_processor_reverse_create(diff_processor, - NULL, scratch_pool); } /* Filter the first path component using a filter processor, until we fixed the diff processing to handle this directly */ - if (root_relpath) - *root_relpath = apr_pstrdup(result_pool, target1); + if (!ddi) + { + diff_processor = svn_diff__tree_processor_filter_create( + diff_processor, target1, scratch_pool); + } else if ((kind1 != svn_node_file && kind2 != svn_node_file) && target1[0] != '\0') { @@ -2048,11 +2074,17 @@ diff_repos_repos(const char **root_relpath, If REVERSE is TRUE, the diff will be reported in reverse. - All other options are the same as those passed to svn_client_diff6(). */ + If DDI is null, anchor the DIFF_PROCESSOR at the requested diff + targets. (This case is used by diff-summarize.) + + If DDI is non-null: Set DDI->orig_path_* to the URLs of the two diff + targets as resolved at the given revisions; set DDI->anchor to a WC path + anchor for PATH2; set DDI->session_relpath to the repository-relpath of + the URL of that same anchor WC path. + + All other options are the same as those passed to svn_client_diff7(). */ static svn_error_t * -diff_repos_wc(const char **root_relpath, - svn_boolean_t *root_is_dir, - struct diff_driver_info_t *ddi, +diff_repos_wc(struct diff_driver_info_t *ddi, const char *path_or_url1, const svn_opt_revision_t *revision1, const svn_opt_revision_t *peg_revision1, @@ -2130,11 +2162,6 @@ diff_repos_wc(const char **root_relpath, target = ""; } - if (root_relpath) - *root_relpath = apr_pstrdup(result_pool, target); - if (root_is_dir) - *root_is_dir = (*target == '\0'); - /* Fetch the URL of the anchor directory. */ SVN_ERR(svn_dirent_get_absolute(&anchor_abspath, anchor, scratch_pool)); SVN_ERR(svn_wc__node_get_url(&anchor_url, ctx->wc_ctx, anchor_abspath, @@ -2143,7 +2170,7 @@ diff_repos_wc(const char **root_relpath, target_url = NULL; } - else /* is_copy && revision2->kind == svn_opt_revision_base */ + else /* is_copy && revision2->kind != svn_opt_revision_base */ { #if 0 svn_node_kind_t kind; @@ -2232,10 +2259,14 @@ diff_repos_wc(const char **root_relpath, anchor_url, result_pool); } + else + { + diff_processor = svn_diff__tree_processor_filter_create( + diff_processor, target, scratch_pool); + } if (reverse) - diff_processor = svn_diff__tree_processor_reverse_create( - diff_processor, NULL, scratch_pool); + diff_processor = svn_diff__tree_processor_reverse_create(diff_processor, scratch_pool); /* Use the diff editor to generate the diff. */ SVN_ERR(svn_ra_has_capability(ra_session, &server_supports_depth, @@ -2311,12 +2342,84 @@ diff_repos_wc(const char **root_relpath, return SVN_NO_ERROR; } +/* Run diff on shelf SHELF_NAME, if it exists. + */ +static svn_error_t * +diff_shelf(const char *shelf_name, + const char *target_abspath, + svn_depth_t depth, + svn_boolean_t ignore_ancestry, + const svn_diff_tree_processor_t *diff_processor, + svn_client_ctx_t *ctx, + apr_pool_t *scratch_pool) +{ + svn_error_t *err; + svn_client__shelf_t *shelf; + svn_client__shelf_version_t *shelf_version; + const char *wc_relpath; + + err = svn_client__shelf_open_existing(&shelf, + shelf_name, target_abspath, + ctx, scratch_pool); + if (err && err->apr_err == SVN_ERR_ILLEGAL_TARGET) + { + svn_error_clear(err); + return SVN_NO_ERROR; + } + else + SVN_ERR(err); + + SVN_ERR(svn_client__shelf_version_open(&shelf_version, + shelf, shelf->max_version, + scratch_pool, scratch_pool)); + wc_relpath = svn_dirent_skip_ancestor(shelf->wc_root_abspath, target_abspath); + SVN_ERR(svn_client__shelf_diff(shelf_version, wc_relpath, + depth, ignore_ancestry, + diff_processor, scratch_pool)); + SVN_ERR(svn_client__shelf_close(shelf, scratch_pool)); + + return SVN_NO_ERROR; +} + +/* Run diff on all shelves named in CHANGELISTS by a changelist name + * of the form "svn:shelf:SHELF_NAME", if they exist. + */ +static svn_error_t * +diff_shelves(const apr_array_header_t *changelists, + const char *target_abspath, + svn_depth_t depth, + svn_boolean_t ignore_ancestry, + const svn_diff_tree_processor_t *diff_processor, + svn_client_ctx_t *ctx, + apr_pool_t *scratch_pool) +{ + static const char PREFIX[] = "svn:shelf:"; + static const int PREFIX_LEN = 10; + int i; + + if (! changelists) + return SVN_NO_ERROR; + for (i = 0; i < changelists->nelts; i++) + { + const char *cl = APR_ARRAY_IDX(changelists, i, const char *); + + if (strncmp(cl, PREFIX, PREFIX_LEN) == 0) + { + const char *shelf_name = cl + PREFIX_LEN; + + SVN_ERR(diff_shelf(shelf_name, target_abspath, + depth, ignore_ancestry, + diff_processor, ctx, scratch_pool)); + } + } + + return SVN_NO_ERROR; +} + /* This is basically just the guts of svn_client_diff[_summarize][_peg]6(). */ static svn_error_t * -do_diff(const char **root_relpath, - svn_boolean_t *root_is_dir, - diff_driver_info_t *ddi, +do_diff(diff_driver_info_t *ddi, const char *path_or_url1, const char *path_or_url2, const svn_opt_revision_t *revision1, @@ -2344,8 +2447,7 @@ do_diff(const char **root_relpath, if (is_repos2) { /* Ignores changelists. */ - SVN_ERR(diff_repos_repos(root_relpath, root_is_dir, - ddi, + SVN_ERR(diff_repos_repos(ddi, path_or_url1, path_or_url2, revision1, revision2, peg_revision, depth, ignore_ancestry, @@ -2355,7 +2457,7 @@ do_diff(const char **root_relpath, } else /* path_or_url2 is a working copy path */ { - SVN_ERR(diff_repos_wc(root_relpath, root_is_dir, ddi, + SVN_ERR(diff_repos_wc(ddi, path_or_url1, revision1, no_peg_revision ? revision1 : peg_revision, @@ -2370,7 +2472,7 @@ do_diff(const char **root_relpath, { if (is_repos2) { - SVN_ERR(diff_repos_wc(root_relpath, root_is_dir, ddi, + SVN_ERR(diff_repos_wc(ddi, path_or_url2, revision2, no_peg_revision ? revision2 : peg_revision, @@ -2394,19 +2496,51 @@ do_diff(const char **root_relpath, SVN_ERR(svn_dirent_get_absolute(&abspath2, path_or_url2, scratch_pool)); - /* ### What about ddi? */ + if (ddi) + { + svn_node_kind_t kind1, kind2; + + SVN_ERR(svn_io_check_resolved_path(abspath1, &kind1, + scratch_pool)); + SVN_ERR(svn_io_check_resolved_path(abspath2, &kind2, + scratch_pool)); + if (kind1 == svn_node_dir && kind2 == svn_node_dir) + { + ddi->anchor = ""; + } + else + { + ddi->anchor = svn_dirent_basename(abspath1, NULL); + } + ddi->orig_path_1 = path_or_url1; + ddi->orig_path_2 = path_or_url2; + } + /* Ignores changelists, ignore_ancestry */ - SVN_ERR(svn_client__arbitrary_nodes_diff(root_relpath, root_is_dir, - abspath1, abspath2, + SVN_ERR(svn_client__arbitrary_nodes_diff(abspath1, abspath2, depth, diff_processor, - ctx, - result_pool, scratch_pool)); + ctx, scratch_pool)); } else { - SVN_ERR(diff_wc_wc(root_relpath, root_is_dir, ddi, - path_or_url1, revision1, + if (ddi) + { + ddi->anchor = path_or_url1; + ddi->orig_path_1 = path_or_url1; + ddi->orig_path_2 = path_or_url2; + } + + { + const char *abspath1; + + SVN_ERR(svn_dirent_get_absolute(&abspath1, path_or_url1, + scratch_pool)); + SVN_ERR(diff_shelves(changelists, abspath1, + depth, ignore_ancestry, + diff_processor, ctx, scratch_pool)); + } + SVN_ERR(diff_wc_wc(path_or_url1, revision1, path_or_url2, revision2, depth, ignore_ancestry, changelists, diff_processor, ctx, @@ -2482,6 +2616,115 @@ create_diff_writer_info(diff_writer_info_t *dwi, return SVN_NO_ERROR; } +/* Set up *DIFF_PROCESSOR and *DDI for normal and git-style diffs (but not + * summary diffs). + */ +static svn_error_t * +get_diff_processor(svn_diff_tree_processor_t **diff_processor, + struct diff_driver_info_t **ddi, + const apr_array_header_t *options, + const char *relative_to_dir, + svn_boolean_t no_diff_added, + svn_boolean_t no_diff_deleted, + svn_boolean_t show_copies_as_adds, + svn_boolean_t ignore_content_type, + svn_boolean_t ignore_properties, + svn_boolean_t properties_only, + svn_boolean_t use_git_diff_format, + svn_boolean_t pretty_print_mergeinfo, + const char *header_encoding, + svn_stream_t *outstream, + svn_stream_t *errstream, + svn_client_ctx_t *ctx, + apr_pool_t *pool) +{ + diff_writer_info_t *dwi = apr_pcalloc(pool, sizeof(*dwi)); + svn_diff_tree_processor_t *processor; + + /* setup callback and baton */ + + SVN_ERR(create_diff_writer_info(dwi, options, + ctx->config, pool)); + dwi->pool = pool; + dwi->outstream = outstream; + dwi->errstream = errstream; + dwi->header_encoding = header_encoding; + + dwi->force_binary = ignore_content_type; + dwi->ignore_properties = ignore_properties; + dwi->properties_only = properties_only; + dwi->relative_to_dir = relative_to_dir; + dwi->use_git_diff_format = use_git_diff_format; + dwi->no_diff_added = no_diff_added; + dwi->no_diff_deleted = no_diff_deleted; + dwi->show_copies_as_adds = show_copies_as_adds; + dwi->pretty_print_mergeinfo = pretty_print_mergeinfo; + + dwi->cancel_func = ctx->cancel_func; + dwi->cancel_baton = ctx->cancel_baton; + + dwi->ddi.wc_ctx = ctx->wc_ctx; + dwi->ddi.session_relpath = NULL; + dwi->ddi.anchor = NULL; + + processor = svn_diff__tree_processor_create(dwi, pool); + + processor->dir_added = diff_dir_added; + processor->dir_changed = diff_dir_changed; + processor->dir_deleted = diff_dir_deleted; + + processor->file_added = diff_file_added; + processor->file_changed = diff_file_changed; + processor->file_deleted = diff_file_deleted; + + *diff_processor = processor; + *ddi = &dwi->ddi; + return SVN_NO_ERROR; +} + +svn_error_t * +svn_client__get_diff_writer_svn( + svn_diff_tree_processor_t **diff_processor, + const char *anchor, + const char *orig_path_1, + const char *orig_path_2, + const apr_array_header_t *options, + const char *relative_to_dir, + svn_boolean_t no_diff_added, + svn_boolean_t no_diff_deleted, + svn_boolean_t show_copies_as_adds, + svn_boolean_t ignore_content_type, + svn_boolean_t ignore_properties, + svn_boolean_t properties_only, + svn_boolean_t pretty_print_mergeinfo, + const char *header_encoding, + svn_stream_t *outstream, + svn_stream_t *errstream, + svn_client_ctx_t *ctx, + apr_pool_t *pool) +{ + struct diff_driver_info_t *ddi; + + SVN_ERR(get_diff_processor(diff_processor, &ddi, + options, + relative_to_dir, + no_diff_added, + no_diff_deleted, + show_copies_as_adds, + ignore_content_type, + ignore_properties, + properties_only, + FALSE /*use_git_diff_format*/, + pretty_print_mergeinfo, + header_encoding, + outstream, errstream, + ctx, pool)); + ddi->anchor = anchor; + ddi->orig_path_1 = orig_path_1; + ddi->orig_path_2 = orig_path_2; + return SVN_NO_ERROR; +} + /*----------------------------------------------------------------------- */ /*** Public Interfaces. ***/ @@ -2519,7 +2762,7 @@ create_diff_writer_info(diff_writer_info_t *dwi, * These cases require server communication. */ svn_error_t * -svn_client_diff6(const apr_array_header_t *options, +svn_client_diff7(const apr_array_header_t *options, const char *path_or_url1, const svn_opt_revision_t *revision1, const char *path_or_url2, @@ -2534,6 +2777,7 @@ svn_client_diff6(const apr_array_header_t *options, svn_boolean_t ignore_properties, svn_boolean_t properties_only, svn_boolean_t use_git_diff_format, + svn_boolean_t pretty_print_mergeinfo, const char *header_encoding, svn_stream_t *outstream, svn_stream_t *errstream, @@ -2541,10 +2785,9 @@ svn_client_diff6(const apr_array_header_t *options, svn_client_ctx_t *ctx, apr_pool_t *pool) { - diff_writer_info_t dwi = { 0 }; svn_opt_revision_t peg_revision; - const svn_diff_tree_processor_t *diff_processor; - svn_diff_tree_processor_t *processor; + svn_diff_tree_processor_t *diff_processor; + struct diff_driver_info_t *ddi; if (ignore_properties && properties_only) return svn_error_create(SVN_ERR_INCORRECT_PARAMS, NULL, @@ -2554,50 +2797,26 @@ svn_client_diff6(const apr_array_header_t *options, /* We will never do a pegged diff from here. */ peg_revision.kind = svn_opt_revision_unspecified; - /* setup callback and baton */ - dwi.ddi.orig_path_1 = path_or_url1; - dwi.ddi.orig_path_2 = path_or_url2; - - SVN_ERR(create_diff_writer_info(&dwi, options, - ctx->config, pool)); - dwi.pool = pool; - dwi.outstream = outstream; - dwi.errstream = errstream; - dwi.header_encoding = header_encoding; - - dwi.force_binary = ignore_content_type; - dwi.ignore_properties = ignore_properties; - dwi.properties_only = properties_only; - dwi.relative_to_dir = relative_to_dir; - dwi.use_git_diff_format = use_git_diff_format; - dwi.no_diff_added = no_diff_added; - dwi.no_diff_deleted = no_diff_deleted; - dwi.show_copies_as_adds = show_copies_as_adds; - - dwi.cancel_func = ctx->cancel_func; - dwi.cancel_baton = ctx->cancel_baton; - - dwi.wc_ctx = ctx->wc_ctx; - dwi.ddi.session_relpath = NULL; - dwi.ddi.anchor = NULL; - - processor = svn_diff__tree_processor_create(&dwi, pool); - - processor->dir_added = diff_dir_added; - processor->dir_changed = diff_dir_changed; - processor->dir_deleted = diff_dir_deleted; - - processor->file_added = diff_file_added; - processor->file_changed = diff_file_changed; - processor->file_deleted = diff_file_deleted; - - diff_processor = processor; - /* --show-copies-as-adds and --git imply --notice-ancestry */ if (show_copies_as_adds || use_git_diff_format) ignore_ancestry = FALSE; - return svn_error_trace(do_diff(NULL, NULL, &dwi.ddi, + SVN_ERR(get_diff_processor(&diff_processor, &ddi, + options, + relative_to_dir, + no_diff_added, + no_diff_deleted, + show_copies_as_adds, + ignore_content_type, + ignore_properties, + properties_only, + use_git_diff_format, + pretty_print_mergeinfo, + header_encoding, + outstream, errstream, + ctx, pool)); + + return svn_error_trace(do_diff(ddi, path_or_url1, path_or_url2, revision1, revision2, &peg_revision, TRUE /* no_peg_revision */, @@ -2607,7 +2826,7 @@ svn_client_diff6(const apr_array_header_t *options, } svn_error_t * -svn_client_diff_peg6(const apr_array_header_t *options, +svn_client_diff_peg7(const apr_array_header_t *options, const char *path_or_url, const svn_opt_revision_t *peg_revision, const svn_opt_revision_t *start_revision, @@ -2622,6 +2841,7 @@ svn_client_diff_peg6(const apr_array_header_t *options, svn_boolean_t ignore_properties, svn_boolean_t properties_only, svn_boolean_t use_git_diff_format, + svn_boolean_t pretty_print_mergeinfo, const char *header_encoding, svn_stream_t *outstream, svn_stream_t *errstream, @@ -2629,59 +2849,34 @@ svn_client_diff_peg6(const apr_array_header_t *options, svn_client_ctx_t *ctx, apr_pool_t *pool) { - diff_writer_info_t dwi = { 0 }; - const svn_diff_tree_processor_t *diff_processor; - svn_diff_tree_processor_t *processor; + svn_diff_tree_processor_t *diff_processor; + struct diff_driver_info_t *ddi; if (ignore_properties && properties_only) return svn_error_create(SVN_ERR_INCORRECT_PARAMS, NULL, _("Cannot ignore properties and show only " "properties at the same time")); - /* setup callback and baton */ - dwi.ddi.orig_path_1 = path_or_url; - dwi.ddi.orig_path_2 = path_or_url; - - SVN_ERR(create_diff_writer_info(&dwi, options, - ctx->config, pool)); - dwi.pool = pool; - dwi.outstream = outstream; - dwi.errstream = errstream; - dwi.header_encoding = header_encoding; - - dwi.force_binary = ignore_content_type; - dwi.ignore_properties = ignore_properties; - dwi.properties_only = properties_only; - dwi.relative_to_dir = relative_to_dir; - dwi.use_git_diff_format = use_git_diff_format; - dwi.no_diff_added = no_diff_added; - dwi.no_diff_deleted = no_diff_deleted; - dwi.show_copies_as_adds = show_copies_as_adds; - - dwi.cancel_func = ctx->cancel_func; - dwi.cancel_baton = ctx->cancel_baton; - - dwi.wc_ctx = ctx->wc_ctx; - dwi.ddi.session_relpath = NULL; - dwi.ddi.anchor = NULL; - - processor = svn_diff__tree_processor_create(&dwi, pool); - - processor->dir_added = diff_dir_added; - processor->dir_changed = diff_dir_changed; - processor->dir_deleted = diff_dir_deleted; - - processor->file_added = diff_file_added; - processor->file_changed = diff_file_changed; - processor->file_deleted = diff_file_deleted; - - diff_processor = processor; - /* --show-copies-as-adds and --git imply --notice-ancestry */ if (show_copies_as_adds || use_git_diff_format) ignore_ancestry = FALSE; - return svn_error_trace(do_diff(NULL, NULL, &dwi.ddi, + SVN_ERR(get_diff_processor(&diff_processor, &ddi, + options, + relative_to_dir, + no_diff_added, + no_diff_deleted, + show_copies_as_adds, + ignore_content_type, + ignore_properties, + properties_only, + use_git_diff_format, + pretty_print_mergeinfo, + header_encoding, + outstream, errstream, + ctx, pool)); + + return svn_error_trace(do_diff(ddi, path_or_url, path_or_url, start_revision, end_revision, peg_revision, FALSE /* no_peg_revision */, @@ -2703,19 +2898,17 @@ svn_client_diff_summarize2(const char *path_or_url1, svn_client_ctx_t *ctx, apr_pool_t *pool) { - const svn_diff_tree_processor_t *diff_processor; + svn_diff_tree_processor_t *diff_processor; svn_opt_revision_t peg_revision; - const char **p_root_relpath; /* We will never do a pegged diff from here. */ peg_revision.kind = svn_opt_revision_unspecified; - SVN_ERR(svn_client__get_diff_summarize_callbacks( - &diff_processor, &p_root_relpath, + SVN_ERR(svn_client__get_diff_summarize_callbacks(&diff_processor, summarize_func, summarize_baton, - path_or_url1, pool, pool)); + pool, pool)); - return svn_error_trace(do_diff(p_root_relpath, NULL, NULL, + return svn_error_trace(do_diff(NULL, path_or_url1, path_or_url2, revision1, revision2, &peg_revision, TRUE /* no_peg_revision */, @@ -2737,15 +2930,13 @@ svn_client_diff_summarize_peg2(const char *path_or_url, svn_client_ctx_t *ctx, apr_pool_t *pool) { - const svn_diff_tree_processor_t *diff_processor; - const char **p_root_relpath; + svn_diff_tree_processor_t *diff_processor; - SVN_ERR(svn_client__get_diff_summarize_callbacks( - &diff_processor, &p_root_relpath, + SVN_ERR(svn_client__get_diff_summarize_callbacks(&diff_processor, summarize_func, summarize_baton, - path_or_url, pool, pool)); + pool, pool)); - return svn_error_trace(do_diff(p_root_relpath, NULL, NULL, + return svn_error_trace(do_diff(NULL, path_or_url, path_or_url, start_revision, end_revision, peg_revision, FALSE /* no_peg_revision */, |