Modified: subversion/branches/pristine-checksum-kind/subversion/libsvn_client/diff.c URL: http://svn.apache.org/viewvc/subversion/branches/pristine-checksum-kind/subversion/libsvn_client/diff.c?rev=1922345&r1=1922344&r2=1922345&view=diff ============================================================================== --- subversion/branches/pristine-checksum-kind/subversion/libsvn_client/diff.c (original) +++ subversion/branches/pristine-checksum-kind/subversion/libsvn_client/diff.c Fri Dec 6 13:59:05 2024 @@ -32,1397 +32,26 @@ #include <apr_strings.h> #include <apr_pools.h> -#include <apr_hash.h> #include "svn_types.h" -#include "svn_hash.h" #include "svn_wc.h" #include "svn_diff.h" #include "svn_mergeinfo.h" #include "svn_client.h" -#include "svn_string.h" #include "svn_error.h" #include "svn_dirent_uri.h" #include "svn_path.h" #include "svn_io.h" -#include "svn_utf.h" -#include "svn_pools.h" -#include "svn_config.h" -#include "svn_props.h" -#include "svn_subst.h" #include "client.h" #include "private/svn_client_shelf.h" +#include "private/svn_client_private.h" #include "private/svn_wc_private.h" -#include "private/svn_diff_private.h" -#include "private/svn_subr_private.h" -#include "private/svn_io_private.h" +#include "private/svn_diff_tree.h" #include "private/svn_ra_private.h" #include "svn_private_config.h" -/* Utilities */ - -#define DIFF_REVNUM_NONEXISTENT ((svn_revnum_t) -100) - -#define MAKE_ERR_BAD_RELATIVE_PATH(path, relative_to_dir) \ - svn_error_createf(SVN_ERR_BAD_RELATIVE_PATH, NULL, \ - _("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, - * and may be used to derive leading path components missing from PATH. - * ANCHOR is the local path where the diff editor is anchored. - * Do all allocations in POOL. */ -static svn_error_t * -make_repos_relpath(const char **repos_relpath, - const char *diff_relpath, - const char *orig_target, - const char *session_relpath, - svn_wc_context_t *wc_ctx, - const char *anchor, - apr_pool_t *result_pool, - apr_pool_t *scratch_pool) -{ - const char *local_abspath; - - if (! session_relpath - || (anchor && !svn_path_is_url(orig_target))) - { - svn_error_t *err; - /* We're doing a WC-WC diff, so we can retrieve all information we - * need from the working copy. */ - SVN_ERR(svn_dirent_get_absolute(&local_abspath, - svn_dirent_join(anchor, diff_relpath, - scratch_pool), - scratch_pool)); - - err = svn_wc__node_get_repos_info(NULL, repos_relpath, NULL, NULL, - wc_ctx, local_abspath, - result_pool, scratch_pool); - - if (!session_relpath - || ! err - || (err && err->apr_err != SVN_ERR_WC_PATH_NOT_FOUND)) - { - return svn_error_trace(err); - } - - /* The path represents a local working copy path, but does not - exist. Fall through to calculate an in-repository location - based on the ra session */ - - /* ### Maybe we should use the nearest existing ancestor instead? */ - svn_error_clear(err); - } - - *repos_relpath = svn_relpath_join(session_relpath, diff_relpath, - result_pool); - - return SVN_NO_ERROR; -} - -/* 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 **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 = 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); - - if (relative_to_dir) - { - /* Possibly adjust the paths shown in the output (see issue #2723). */ - const char *child_path = svn_dirent_is_child(relative_to_dir, new_path, - result_pool); - - if (child_path) - new_path = child_path; - else if (! strcmp(relative_to_dir, new_path)) - new_path = "."; - else - return MAKE_ERR_BAD_RELATIVE_PATH(new_path, relative_to_dir); - } - - { - apr_size_t len; - svn_boolean_t is_url1; - svn_boolean_t is_url2; - /* ### Holy cow. Due to anchor/target weirdness, we can't - simply join dwi->orig_path_1 with path, ditto for - orig_path_2. That will work when they're directory URLs, but - not for file URLs. Nor can we just use anchor1 and anchor2 - from do_diff(), at least not without some more logic here. - What a nightmare. - - For now, to distinguish the two paths, we'll just put the - unique portions of the original targets in parentheses after - the received path, with ellipses for handwaving. This makes - the labels a bit clumsy, but at least distinctive. Better - solutions are possible, they'll just take more thought. */ - - /* ### 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); - - if (is_url1 && is_url2) - len = strlen(svn_uri_get_longest_ancestor(new_path1, new_path2, - scratch_pool)); - else if (!is_url1 && !is_url2) - len = strlen(svn_dirent_get_longest_ancestor(new_path1, new_path2, - scratch_pool)); - else - len = 0; /* Path and URL */ - - new_path1 += len; - new_path2 += len; - } - - /* ### Should diff labels print paths in local style? Is there - already a standard for this? In any case, this code depends on - a particular style, so not calling svn_dirent_local_style() on the - paths below.*/ - - if (new_path[0] == '\0') - new_path = "."; - - if (new_path1[0] == '\0') - new_path1 = new_path; - else if (svn_path_is_url(new_path1)) - new_path1 = apr_psprintf(result_pool, "%s\t(%s)", new_path, new_path1); - else if (new_path1[0] == '/') - new_path1 = apr_psprintf(result_pool, "%s\t(...%s)", new_path, new_path1); - else - new_path1 = apr_psprintf(result_pool, "%s\t(.../%s)", new_path, new_path1); - - if (new_path2[0] == '\0') - new_path2 = new_path; - else if (svn_path_is_url(new_path2)) - new_path2 = apr_psprintf(result_pool, "%s\t(%s)", new_path, new_path2); - else if (new_path2[0] == '/') - new_path2 = apr_psprintf(result_pool, "%s\t(...%s)", new_path, new_path2); - else - new_path2 = apr_psprintf(result_pool, "%s\t(.../%s)", new_path, new_path2); - - *index_path = new_path; - *label_path1 = new_path1; - *label_path2 = new_path2; - - return SVN_NO_ERROR; -} - - -/* Generate a label for the diff output for file PATH at revision REVNUM. - If REVNUM is invalid then it is assumed to be the current working - copy. Assumes the paths are already in the desired style (local - vs internal). Allocate the label in RESULT-POOL. */ -static const char * -diff_label(const char *path, - svn_revnum_t revnum, - apr_pool_t *result_pool) -{ - const char *label; - if (revnum >= 0) - label = apr_psprintf(result_pool, _("%s\t(revision %ld)"), path, revnum); - else if (revnum == DIFF_REVNUM_NONEXISTENT) - label = apr_psprintf(result_pool, _("%s\t(nonexistent)"), path); - else /* SVN_INVALID_REVNUM */ - label = apr_psprintf(result_pool, _("%s\t(working copy)"), path); - - return label; -} - -/* Standard modes produced in git style diffs */ -static const int exec_mode = 0755; -static const int noexec_mode = 0644; -static const int kind_file_mode = 0100000; -/*static const kind_dir_mode = 0040000;*/ -static const int kind_symlink_mode = 0120000; - -/* Print a git diff header for an addition within a diff between PATH1 and - * PATH2 to the stream OS using HEADER_ENCODING. */ -static svn_error_t * -print_git_diff_header_added(svn_stream_t *os, const char *header_encoding, - const char *path1, const char *path2, - svn_boolean_t exec_bit, - svn_boolean_t symlink_bit, - apr_pool_t *scratch_pool) -{ - int new_mode = (exec_bit ? exec_mode : noexec_mode) - | (symlink_bit ? kind_symlink_mode : kind_file_mode); - - SVN_ERR(svn_stream_printf_from_utf8(os, header_encoding, scratch_pool, - "diff --git a/%s b/%s%s", - path1, path2, APR_EOL_STR)); - SVN_ERR(svn_stream_printf_from_utf8(os, header_encoding, scratch_pool, - "new file mode %06o" APR_EOL_STR, - new_mode)); - return SVN_NO_ERROR; -} - -/* Print a git diff header for a deletion within a diff between PATH1 and - * PATH2 to the stream OS using HEADER_ENCODING. */ -static svn_error_t * -print_git_diff_header_deleted(svn_stream_t *os, const char *header_encoding, - const char *path1, const char *path2, - svn_boolean_t exec_bit, - svn_boolean_t symlink_bit, - apr_pool_t *scratch_pool) -{ - int old_mode = (exec_bit ? exec_mode : noexec_mode) - | (symlink_bit ? kind_symlink_mode : kind_file_mode); - SVN_ERR(svn_stream_printf_from_utf8(os, header_encoding, scratch_pool, - "diff --git a/%s b/%s%s", - path1, path2, APR_EOL_STR)); - SVN_ERR(svn_stream_printf_from_utf8(os, header_encoding, scratch_pool, - "deleted file mode %06o" APR_EOL_STR, - old_mode)); - return SVN_NO_ERROR; -} - -/* Print a git diff header for a copy from COPYFROM_PATH to PATH to the stream - * OS using HEADER_ENCODING. */ -static svn_error_t * -print_git_diff_header_copied(svn_stream_t *os, const char *header_encoding, - const char *copyfrom_path, - svn_revnum_t copyfrom_rev, - const char *path, - apr_pool_t *scratch_pool) -{ - SVN_ERR(svn_stream_printf_from_utf8(os, header_encoding, scratch_pool, - "diff --git a/%s b/%s%s", - copyfrom_path, path, APR_EOL_STR)); - if (copyfrom_rev != SVN_INVALID_REVNUM) - SVN_ERR(svn_stream_printf_from_utf8(os, header_encoding, scratch_pool, - "copy from %s@%ld%s", copyfrom_path, - copyfrom_rev, APR_EOL_STR)); - else - SVN_ERR(svn_stream_printf_from_utf8(os, header_encoding, scratch_pool, - "copy from %s%s", copyfrom_path, - APR_EOL_STR)); - SVN_ERR(svn_stream_printf_from_utf8(os, header_encoding, scratch_pool, - "copy to %s%s", path, APR_EOL_STR)); - return SVN_NO_ERROR; -} - -/* Print a git diff header for a rename from COPYFROM_PATH to PATH to the - * stream OS using HEADER_ENCODING. */ -static svn_error_t * -print_git_diff_header_renamed(svn_stream_t *os, const char *header_encoding, - const char *copyfrom_path, const char *path, - apr_pool_t *scratch_pool) -{ - SVN_ERR(svn_stream_printf_from_utf8(os, header_encoding, scratch_pool, - "diff --git a/%s b/%s%s", - copyfrom_path, path, APR_EOL_STR)); - SVN_ERR(svn_stream_printf_from_utf8(os, header_encoding, scratch_pool, - "rename from %s%s", copyfrom_path, - APR_EOL_STR)); - SVN_ERR(svn_stream_printf_from_utf8(os, header_encoding, scratch_pool, - "rename to %s%s", path, APR_EOL_STR)); - return SVN_NO_ERROR; -} - -/* Print a git diff header for a modification within a diff between PATH1 and - * PATH2 to the stream OS using HEADER_ENCODING. */ -static svn_error_t * -print_git_diff_header_modified(svn_stream_t *os, const char *header_encoding, - const char *path1, const char *path2, - apr_pool_t *scratch_pool) -{ - SVN_ERR(svn_stream_printf_from_utf8(os, header_encoding, scratch_pool, - "diff --git a/%s b/%s%s", - path1, path2, APR_EOL_STR)); - return SVN_NO_ERROR; -} - -/* Helper function for print_git_diff_header */ -static svn_error_t * -maybe_print_mode_change(svn_stream_t *os, - const char *header_encoding, - svn_boolean_t exec_bit1, - svn_boolean_t exec_bit2, - svn_boolean_t symlink_bit1, - svn_boolean_t symlink_bit2, - const char *git_index_shas, - apr_pool_t *scratch_pool) -{ - int old_mode = (exec_bit1 ? exec_mode : noexec_mode) - | (symlink_bit1 ? kind_symlink_mode : kind_file_mode); - int new_mode = (exec_bit2 ? exec_mode : noexec_mode) - | (symlink_bit2 ? kind_symlink_mode : kind_file_mode); - if (old_mode == new_mode) - { - if (git_index_shas) - SVN_ERR(svn_stream_printf_from_utf8(os, header_encoding, scratch_pool, - "index %s %06o" APR_EOL_STR, - git_index_shas, old_mode)); - return SVN_NO_ERROR; - } - - SVN_ERR(svn_stream_printf_from_utf8(os, header_encoding, scratch_pool, - "old mode %06o" APR_EOL_STR, old_mode)); - SVN_ERR(svn_stream_printf_from_utf8(os, header_encoding, scratch_pool, - "new mode %06o" APR_EOL_STR, new_mode)); - return SVN_NO_ERROR; -} - -/* 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. - * - * 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, - 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, - SVN_PROP_EXECUTABLE) != NULL); - svn_boolean_t symlink_bit1 = (svn_prop_get_value(left_props, - SVN_PROP_SPECIAL) != NULL); - 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, - repos_relpath1, repos_relpath2, - exec_bit1, symlink_bit1, - scratch_pool)); - *label1 = diff_label(apr_psprintf(scratch_pool, "a/%s", repos_relpath1), - rev1, scratch_pool); - *label2 = diff_label(apr_psprintf(scratch_pool, "b/%s", repos_relpath2), - rev2, scratch_pool); - - } - else if (operation == svn_diff_op_copied) - { - SVN_ERR(print_git_diff_header_copied(os, header_encoding, - copyfrom_path, copyfrom_rev, - repos_relpath2, - scratch_pool)); - *label1 = diff_label(apr_psprintf(scratch_pool, "a/%s", copyfrom_path), - rev1, scratch_pool); - *label2 = diff_label(apr_psprintf(scratch_pool, "b/%s", repos_relpath2), - rev2, scratch_pool); - SVN_ERR(maybe_print_mode_change(os, header_encoding, - exec_bit1, exec_bit2, - symlink_bit1, symlink_bit2, - git_index_shas, - scratch_pool)); - } - else if (operation == svn_diff_op_added) - { - SVN_ERR(print_git_diff_header_added(os, header_encoding, - repos_relpath1, repos_relpath2, - exec_bit2, symlink_bit2, - scratch_pool)); - *label1 = diff_label(apr_psprintf(scratch_pool, "a/%s", repos_relpath1), - rev1, scratch_pool); - *label2 = diff_label(apr_psprintf(scratch_pool, "b/%s", repos_relpath2), - rev2, scratch_pool); - } - else if (operation == svn_diff_op_modified) - { - SVN_ERR(print_git_diff_header_modified(os, header_encoding, - repos_relpath1, repos_relpath2, - scratch_pool)); - *label1 = diff_label(apr_psprintf(scratch_pool, "a/%s", repos_relpath1), - rev1, scratch_pool); - *label2 = diff_label(apr_psprintf(scratch_pool, "b/%s", repos_relpath2), - rev2, scratch_pool); - SVN_ERR(maybe_print_mode_change(os, header_encoding, - exec_bit1, exec_bit2, - symlink_bit1, symlink_bit2, - git_index_shas, - scratch_pool)); - } - else if (operation == svn_diff_op_moved) - { - SVN_ERR(print_git_diff_header_renamed(os, header_encoding, - copyfrom_path, repos_relpath2, - scratch_pool)); - *label1 = diff_label(apr_psprintf(scratch_pool, "a/%s", copyfrom_path), - rev1, scratch_pool); - *label2 = diff_label(apr_psprintf(scratch_pool, "b/%s", repos_relpath2), - rev2, scratch_pool); - SVN_ERR(maybe_print_mode_change(os, header_encoding, - exec_bit1, exec_bit2, - symlink_bit1, symlink_bit2, - git_index_shas, - scratch_pool)); - } - - 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_diff7(), which is probably stdout. - - ### FIXME needs proper docstring - - If USE_GIT_DIFF_FORMAT is TRUE, print git diff headers, which always - 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, - svn_revnum_t rev1, - svn_revnum_t rev2, - const char *encoding, - svn_stream_t *outstream, - const char *relative_to_dir, - svn_boolean_t show_diff_header, - svn_boolean_t use_git_diff_format, - svn_boolean_t pretty_print_mergeinfo, - const diff_driver_info_t *ddi, - svn_cancel_func_t cancel_func, - void *cancel_baton, - apr_pool_t *scratch_pool) -{ - const char *repos_relpath1 = NULL; - const char *index_path; - const char *label_path1, *label_path2; - - if (use_git_diff_format) - { - 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, - &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) - { - const char *label1; - const char *label2; - - label1 = diff_label(label_path1, rev1, scratch_pool); - label2 = diff_label(label_path2, rev2, scratch_pool); - - 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, - rev1, rev2, - diff_relpath, - NULL, SVN_INVALID_REVNUM, - left_props, right_props, - NULL, - encoding, ddi, scratch_pool)); - - /* --- label1 - * +++ label2 */ - SVN_ERR(svn_diff__unidiff_write_header( - outstream, encoding, label1, label2, scratch_pool)); - } - - SVN_ERR(svn_stream_printf_from_utf8(outstream, encoding, scratch_pool, - APR_EOL_STR - "Property changes on: %s" - APR_EOL_STR, - use_git_diff_format - ? repos_relpath1 - : index_path)); - - SVN_ERR(svn_stream_printf_from_utf8(outstream, encoding, scratch_pool, - SVN_DIFF__UNDER_STRING APR_EOL_STR)); - - SVN_ERR(svn_diff__display_prop_diffs( - outstream, encoding, propchanges, left_props, - pretty_print_mergeinfo, - -1 /* context_size */, - cancel_func, cancel_baton, scratch_pool)); - - return SVN_NO_ERROR; -} - -/*-----------------------------------------------------------------*/ - -/*** Callbacks for 'svn diff', invoked by the repos-diff editor. ***/ - -/* Diff writer state */ -typedef struct diff_writer_info_t -{ - /* If non-null, the external diff command to invoke. */ - const char *diff_cmd; - - /* This is allocated in this struct's pool or a higher-up pool. */ - union { - /* If 'diff_cmd' is null, then this is the parsed options to - pass to the internal libsvn_diff implementation. */ - svn_diff_file_options_t *for_internal; - /* Else if 'diff_cmd' is non-null, then... */ - struct { - /* ...this is an argument array for the external command, and */ - const char **argv; - /* ...this is the length of argv. */ - int argc; - } for_external; - } options; - - apr_pool_t *pool; - svn_stream_t *outstream; - svn_stream_t *errstream; - - const char *header_encoding; - - /* Set this if you want diff output even for binary files. */ - svn_boolean_t force_binary; - - /* The directory that diff target paths should be considered as - relative to for output generation (see issue #2723). */ - const char *relative_to_dir; - - /* Whether property differences are ignored. */ - svn_boolean_t ignore_properties; - - /* Whether to show only property changes. */ - svn_boolean_t properties_only; - - /* Whether we're producing a git-style diff. */ - svn_boolean_t use_git_diff_format; - - /* Whether addition of a file is summarized versus showing a full diff. */ - svn_boolean_t no_diff_added; - - /* Whether deletion of a file is summarized versus showing a full diff. */ - svn_boolean_t no_diff_deleted; - - /* 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_cancel_func_t cancel_func; - void *cancel_baton; - - struct diff_driver_info_t ddi; -} diff_writer_info_t; - -/* An helper for diff_dir_props_changed, diff_file_changed and diff_file_added - */ -static svn_error_t * -diff_props_changed(const char *diff_relpath, - svn_revnum_t rev1, - svn_revnum_t rev2, - const apr_array_header_t *propchanges, - apr_hash_t *left_props, - apr_hash_t *right_props, - svn_boolean_t show_diff_header, - diff_writer_info_t *dwi, - apr_pool_t *scratch_pool) -{ - apr_array_header_t *props; - - /* If property differences are ignored, there's nothing to do. */ - if (dwi->ignore_properties) - return SVN_NO_ERROR; - - SVN_ERR(svn_categorize_props(propchanges, NULL, NULL, &props, - scratch_pool)); - - if (props->nelts > 0) - { - /* We're using the revnums from the dwi since there's - * no revision argument to the svn_wc_diff_callback_t - * dir_props_changed(). */ - SVN_ERR(display_prop_diffs(props, left_props, right_props, - diff_relpath, - rev1, - rev2, - dwi->header_encoding, - dwi->outstream, - dwi->relative_to_dir, - show_diff_header, - dwi->use_git_diff_format, - dwi->pretty_print_mergeinfo, - &dwi->ddi, - dwi->cancel_func, - dwi->cancel_baton, - scratch_pool)); - } - - return SVN_NO_ERROR; -} - -/* Given a file ORIG_TMPFILE, return a path to a temporary file that lives at - * least as long as RESULT_POOL, containing the git-like represention of - * ORIG_TMPFILE */ -static svn_error_t * -transform_link_to_git(const char **new_tmpfile, - const char **git_sha1, - const char *orig_tmpfile, - apr_pool_t *result_pool, - apr_pool_t *scratch_pool) -{ - apr_file_t *orig; - apr_file_t *gitlike; - svn_stringbuf_t *line; - - *git_sha1 = NULL; - - SVN_ERR(svn_io_file_open(&orig, orig_tmpfile, APR_READ, APR_OS_DEFAULT, - scratch_pool)); - SVN_ERR(svn_io_open_unique_file3(&gitlike, new_tmpfile, NULL, - svn_io_file_del_on_pool_cleanup, - result_pool, scratch_pool)); - - SVN_ERR(svn_io_file_readline(orig, &line, NULL, NULL, 2 * APR_PATH_MAX + 2, - scratch_pool, scratch_pool)); - - if (line->len > 5 && !strncmp(line->data, "link ", 5)) - { - const char *sz_str; - svn_checksum_t *checksum; - - svn_stringbuf_remove(line, 0, 5); - - SVN_ERR(svn_io_file_write_full(gitlike, line->data, line->len, - NULL, scratch_pool)); - - /* git calculates the sha over "blob X\0" + the actual data, - where X is the decimal size of the blob. */ - sz_str = apr_psprintf(scratch_pool, "blob %u", (unsigned int)line->len); - svn_stringbuf_insert(line, 0, sz_str, strlen(sz_str) + 1); - - SVN_ERR(svn_checksum(&checksum, svn_checksum_sha1, - line->data, line->len, scratch_pool)); - - *git_sha1 = svn_checksum_to_cstring(checksum, result_pool); - } - else - { - /* Not a link... so can't convert */ - *new_tmpfile = apr_pstrdup(result_pool, orig_tmpfile); - } - - SVN_ERR(svn_io_file_close(orig, scratch_pool)); - SVN_ERR(svn_io_file_close(gitlike, scratch_pool)); - return SVN_NO_ERROR; -} - -/* Show differences between TMPFILE1 and TMPFILE2. DIFF_RELPATH, REV1, and - 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. - - Set *WROTE_HEADER to TRUE if a diff header was written */ -static svn_error_t * -diff_content_changed(svn_boolean_t *wrote_header, - const char *diff_relpath, - const char *tmpfile1, - const char *tmpfile2, - svn_revnum_t rev1, - svn_revnum_t rev2, - apr_hash_t *left_props, - apr_hash_t *right_props, - svn_diff_operation_kind_t operation, - svn_boolean_t force_diff, - const char *copyfrom_path, - svn_revnum_t copyfrom_rev, - diff_writer_info_t *dwi, - apr_pool_t *scratch_pool) -{ - const char *rel_to_dir = dwi->relative_to_dir; - svn_stream_t *outstream = dwi->outstream; - const char *label1, *label2; - svn_boolean_t mt1_binary = FALSE, mt2_binary = FALSE; - 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; - - /* If only property differences are shown, there's nothing to do. */ - if (dwi->properties_only) - return SVN_NO_ERROR; - - /* Generate the diff headers. */ - 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(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. - Print a warning and exit. */ - if (mimetype1) - mt1_binary = svn_mime_type_is_binary(mimetype1); - if (mimetype2) - mt2_binary = svn_mime_type_is_binary(mimetype2); - - if (dwi->use_git_diff_format) - { - const char *l_hash = NULL; - const char *r_hash = NULL; - - /* Change symlinks to their 'git like' plain format */ - if (svn_prop_get_value(left_props, SVN_PROP_SPECIAL)) - SVN_ERR(transform_link_to_git(&tmpfile1, &l_hash, tmpfile1, - scratch_pool, scratch_pool)); - if (svn_prop_get_value(right_props, SVN_PROP_SPECIAL)) - SVN_ERR(transform_link_to_git(&tmpfile2, &r_hash, tmpfile2, - scratch_pool, scratch_pool)); - - if (l_hash && r_hash) - { - /* The symlink has changed. But we can't tell the user of the - diff whether we are writing git diffs or svn diffs of the - symlink... except when we add a git-like index line */ - - l_hash = apr_pstrndup(scratch_pool, l_hash, 8); - r_hash = apr_pstrndup(scratch_pool, r_hash, 8); - - index_shas = apr_psprintf(scratch_pool, "%8s..%8s", - l_hash, r_hash); - } - } - - if (! dwi->force_binary && (mt1_binary || mt2_binary)) - { - /* Print out the diff header. */ - SVN_ERR(print_diff_index_header(outstream, dwi->header_encoding, - index_path, "", scratch_pool)); - *wrote_header = TRUE; - - /* ### Print git diff headers. */ - - if (dwi->use_git_diff_format) - { - svn_stream_t *left_stream; - svn_stream_t *right_stream; - - SVN_ERR(print_git_diff_header(outstream, - &label1, &label2, - operation, - rev1, rev2, - diff_relpath, - copyfrom_path, copyfrom_rev, - left_props, right_props, - index_shas, - dwi->header_encoding, - &dwi->ddi, scratch_pool)); - - SVN_ERR(svn_stream_open_readonly(&left_stream, tmpfile1, - scratch_pool, scratch_pool)); - SVN_ERR(svn_stream_open_readonly(&right_stream, tmpfile2, - scratch_pool, scratch_pool)); - SVN_ERR(svn_diff_output_binary(outstream, - left_stream, right_stream, - dwi->cancel_func, dwi->cancel_baton, - scratch_pool)); - } - else - { - SVN_ERR(svn_stream_printf_from_utf8(outstream, - dwi->header_encoding, scratch_pool, - _("Cannot display: file marked as a binary type.%s"), - APR_EOL_STR)); - - if (mt1_binary && !mt2_binary) - SVN_ERR(svn_stream_printf_from_utf8(outstream, - dwi->header_encoding, scratch_pool, - "svn:mime-type = %s" APR_EOL_STR, mimetype1)); - else if (mt2_binary && !mt1_binary) - SVN_ERR(svn_stream_printf_from_utf8(outstream, - dwi->header_encoding, scratch_pool, - "svn:mime-type = %s" APR_EOL_STR, mimetype2)); - else if (mt1_binary && mt2_binary) - { - if (strcmp(mimetype1, mimetype2) == 0) - SVN_ERR(svn_stream_printf_from_utf8(outstream, - dwi->header_encoding, scratch_pool, - "svn:mime-type = %s" APR_EOL_STR, - mimetype1)); - else - SVN_ERR(svn_stream_printf_from_utf8(outstream, - dwi->header_encoding, scratch_pool, - "svn:mime-type = (%s, %s)" APR_EOL_STR, - mimetype1, mimetype2)); - } - } - - /* Exit early. */ - return SVN_NO_ERROR; - } - - - if (dwi->diff_cmd) - { - svn_stream_t *errstream = dwi->errstream; - apr_file_t *outfile; - apr_file_t *errfile; - const char *outfilename; - const char *errfilename; - svn_stream_t *stream; - int exitcode; - - /* Print out the diff header. */ - 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 - * ### is up to the external diff application. We may be dealing with - * ### a non-git compatible diff application.*/ - - /* We deal in streams, but svn_io_run_diff2() deals in file handles, - so we may need to make temporary files and then copy the contents - to our stream. */ - outfile = svn_stream__aprfile(outstream); - if (outfile) - outfilename = NULL; - else - SVN_ERR(svn_io_open_unique_file3(&outfile, &outfilename, NULL, - svn_io_file_del_on_pool_cleanup, - scratch_pool, scratch_pool)); - - errfile = svn_stream__aprfile(errstream); - if (errfile) - errfilename = NULL; - else - SVN_ERR(svn_io_open_unique_file3(&errfile, &errfilename, NULL, - svn_io_file_del_on_pool_cleanup, - scratch_pool, scratch_pool)); - - SVN_ERR(svn_io_run_diff2(".", - dwi->options.for_external.argv, - dwi->options.for_external.argc, - label1, label2, - tmpfile1, tmpfile2, - &exitcode, outfile, errfile, - dwi->diff_cmd, scratch_pool)); - - /* Now, open and copy our files to our output streams. */ - if (outfilename) - { - SVN_ERR(svn_io_file_close(outfile, scratch_pool)); - SVN_ERR(svn_stream_open_readonly(&stream, outfilename, - scratch_pool, scratch_pool)); - SVN_ERR(svn_stream_copy3(stream, svn_stream_disown(outstream, - scratch_pool), - NULL, NULL, scratch_pool)); - } - if (errfilename) - { - SVN_ERR(svn_io_file_close(errfile, scratch_pool)); - SVN_ERR(svn_stream_open_readonly(&stream, errfilename, - scratch_pool, scratch_pool)); - SVN_ERR(svn_stream_copy3(stream, svn_stream_disown(errstream, - scratch_pool), - NULL, NULL, scratch_pool)); - } - } - else /* use libsvn_diff to generate the diff */ - { - svn_diff_t *diff; - - SVN_ERR(svn_diff_file_diff_2(&diff, tmpfile1, tmpfile2, - dwi->options.for_internal, - scratch_pool)); - - if (force_diff - || dwi->use_git_diff_format - || svn_diff_contains_diffs(diff)) - { - /* Print out the diff header. */ - SVN_ERR(print_diff_index_header(outstream, dwi->header_encoding, - index_path, "", scratch_pool)); - *wrote_header = TRUE; - - if (dwi->use_git_diff_format) - { - SVN_ERR(print_git_diff_header(outstream, - &label1, &label2, - operation, - rev1, rev2, - diff_relpath, - copyfrom_path, copyfrom_rev, - left_props, right_props, - index_shas, - dwi->header_encoding, - &dwi->ddi, scratch_pool)); - } - - /* Output the actual diff */ - if (force_diff || svn_diff_contains_diffs(diff)) - SVN_ERR(svn_diff_file_output_unified4(outstream, diff, - tmpfile1, tmpfile2, label1, label2, - dwi->header_encoding, rel_to_dir, - dwi->options.for_internal->show_c_function, - dwi->options.for_internal->context_size, - dwi->cancel_func, dwi->cancel_baton, - scratch_pool)); - } - } - - return SVN_NO_ERROR; -} - -/* An svn_diff_tree_processor_t callback. */ -static svn_error_t * -diff_file_changed(const char *relpath, - const svn_diff_source_t *left_source, - const svn_diff_source_t *right_source, - const char *left_file, - const char *right_file, - /*const*/ apr_hash_t *left_props, - /*const*/ apr_hash_t *right_props, - svn_boolean_t file_modified, - const apr_array_header_t *prop_changes, - void *file_baton, - const struct svn_diff_tree_processor_t *processor, - apr_pool_t *scratch_pool) -{ - diff_writer_info_t *dwi = processor->baton; - svn_boolean_t wrote_header = FALSE; - - if (file_modified) - SVN_ERR(diff_content_changed(&wrote_header, relpath, - left_file, right_file, - left_source->revision, - right_source->revision, - left_props, right_props, - svn_diff_op_modified, FALSE, - NULL, - SVN_INVALID_REVNUM, dwi, - scratch_pool)); - if (prop_changes->nelts > 0) - SVN_ERR(diff_props_changed(relpath, - left_source->revision, - right_source->revision, prop_changes, - left_props, right_props, !wrote_header, - dwi, scratch_pool)); - return SVN_NO_ERROR; -} - -/* Because the repos-diff editor passes at least one empty file to - each of these next two functions, they can be dumb wrappers around - the main workhorse routine. */ - -/* An svn_diff_tree_processor_t callback. */ -static svn_error_t * -diff_file_added(const char *relpath, - const svn_diff_source_t *copyfrom_source, - const svn_diff_source_t *right_source, - const char *copyfrom_file, - const char *right_file, - /*const*/ apr_hash_t *copyfrom_props, - /*const*/ apr_hash_t *right_props, - void *file_baton, - const struct svn_diff_tree_processor_t *processor, - apr_pool_t *scratch_pool) -{ - diff_writer_info_t *dwi = processor->baton; - svn_boolean_t wrote_header = FALSE; - const char *left_file; - apr_hash_t *left_props; - apr_array_header_t *prop_changes; - - if (dwi->no_diff_added) - { - const char *index_path = relpath; - - if (dwi->ddi.anchor) - index_path = svn_dirent_join(dwi->ddi.anchor, relpath, - scratch_pool); - - SVN_ERR(print_diff_index_header(dwi->outstream, dwi->header_encoding, - index_path, " (added)", - scratch_pool)); - wrote_header = TRUE; - return SVN_NO_ERROR; - } - - /* During repos->wc diff of a copy revision numbers obtained - * from the working copy are always SVN_INVALID_REVNUM. */ - if (copyfrom_source && !dwi->show_copies_as_adds) - { - left_file = copyfrom_file; - left_props = copyfrom_props ? copyfrom_props : apr_hash_make(scratch_pool); - } - else - { - if (!dwi->empty_file) - SVN_ERR(svn_io_open_unique_file3(NULL, &dwi->empty_file, - NULL, svn_io_file_del_on_pool_cleanup, - dwi->pool, scratch_pool)); - - left_file = dwi->empty_file; - left_props = apr_hash_make(scratch_pool); - - copyfrom_source = NULL; - copyfrom_file = NULL; - } - - SVN_ERR(svn_prop_diffs(&prop_changes, right_props, left_props, scratch_pool)); - - if (copyfrom_source && right_file) - SVN_ERR(diff_content_changed(&wrote_header, relpath, - left_file, right_file, - copyfrom_source->revision, - right_source->revision, - left_props, right_props, - copyfrom_source->moved_from_relpath - ? svn_diff_op_moved - : svn_diff_op_copied, - TRUE /* force diff output */, - copyfrom_source->moved_from_relpath - ? copyfrom_source->moved_from_relpath - : copyfrom_source->repos_relpath, - copyfrom_source->revision, - dwi, scratch_pool)); - else if (right_file) - SVN_ERR(diff_content_changed(&wrote_header, relpath, - left_file, right_file, - DIFF_REVNUM_NONEXISTENT, - right_source->revision, - left_props, right_props, - svn_diff_op_added, - TRUE /* force diff output */, - NULL, SVN_INVALID_REVNUM, - dwi, scratch_pool)); - - if (prop_changes->nelts > 0) - SVN_ERR(diff_props_changed(relpath, - copyfrom_source ? copyfrom_source->revision - : DIFF_REVNUM_NONEXISTENT, - right_source->revision, - prop_changes, - left_props, right_props, - ! wrote_header, dwi, scratch_pool)); - - return SVN_NO_ERROR; -} - -/* An svn_diff_tree_processor_t callback. */ -static svn_error_t * -diff_file_deleted(const char *relpath, - const svn_diff_source_t *left_source, - const char *left_file, - /*const*/ apr_hash_t *left_props, - void *file_baton, - const struct svn_diff_tree_processor_t *processor, - apr_pool_t *scratch_pool) -{ - diff_writer_info_t *dwi = processor->baton; - - if (dwi->no_diff_deleted) - { - const char *index_path = relpath; - - if (dwi->ddi.anchor) - index_path = svn_dirent_join(dwi->ddi.anchor, relpath, - scratch_pool); - - SVN_ERR(print_diff_index_header(dwi->outstream, dwi->header_encoding, - index_path, " (deleted)", - scratch_pool)); - } - else - { - svn_boolean_t wrote_header = FALSE; - - if (!dwi->empty_file) - SVN_ERR(svn_io_open_unique_file3(NULL, &dwi->empty_file, - NULL, svn_io_file_del_on_pool_cleanup, - dwi->pool, scratch_pool)); - - if (left_file) - SVN_ERR(diff_content_changed(&wrote_header, relpath, - left_file, dwi->empty_file, - left_source->revision, - DIFF_REVNUM_NONEXISTENT, - left_props, - NULL, - svn_diff_op_deleted, FALSE, - NULL, SVN_INVALID_REVNUM, - dwi, - scratch_pool)); - - if (left_props && apr_hash_count(left_props)) - { - apr_array_header_t *prop_changes; - - SVN_ERR(svn_prop_diffs(&prop_changes, apr_hash_make(scratch_pool), - left_props, scratch_pool)); - - SVN_ERR(diff_props_changed(relpath, - left_source->revision, - DIFF_REVNUM_NONEXISTENT, - prop_changes, - left_props, NULL, - ! wrote_header, dwi, scratch_pool)); - } - } - - return SVN_NO_ERROR; -} - -/* An svn_wc_diff_callbacks4_t function. */ -static svn_error_t * -diff_dir_changed(const char *relpath, - const svn_diff_source_t *left_source, - const svn_diff_source_t *right_source, - /*const*/ apr_hash_t *left_props, - /*const*/ apr_hash_t *right_props, - const apr_array_header_t *prop_changes, - void *dir_baton, - const struct svn_diff_tree_processor_t *processor, - apr_pool_t *scratch_pool) -{ - diff_writer_info_t *dwi = processor->baton; - - SVN_ERR(diff_props_changed(relpath, - left_source->revision, - right_source->revision, - prop_changes, - left_props, right_props, - TRUE /* show_diff_header */, - dwi, - scratch_pool)); - - return SVN_NO_ERROR; -} - -/* An svn_diff_tree_processor_t callback. */ -static svn_error_t * -diff_dir_added(const char *relpath, - const svn_diff_source_t *copyfrom_source, - const svn_diff_source_t *right_source, - /*const*/ apr_hash_t *copyfrom_props, - /*const*/ apr_hash_t *right_props, - void *dir_baton, - const struct svn_diff_tree_processor_t *processor, - apr_pool_t *scratch_pool) -{ - diff_writer_info_t *dwi = processor->baton; - apr_hash_t *left_props; - apr_array_header_t *prop_changes; - - if (dwi->no_diff_added) - return SVN_NO_ERROR; - - if (copyfrom_source && !dwi->show_copies_as_adds) - { - left_props = copyfrom_props ? copyfrom_props - : apr_hash_make(scratch_pool); - } - else - { - left_props = apr_hash_make(scratch_pool); - copyfrom_source = NULL; - } - - SVN_ERR(svn_prop_diffs(&prop_changes, right_props, left_props, - scratch_pool)); - - return svn_error_trace(diff_props_changed(relpath, - copyfrom_source ? copyfrom_source->revision - : DIFF_REVNUM_NONEXISTENT, - right_source->revision, - prop_changes, - left_props, right_props, - TRUE /* show_diff_header */, - dwi, - scratch_pool)); -} - -/* An svn_diff_tree_processor_t callback. */ -static svn_error_t * -diff_dir_deleted(const char *relpath, - const svn_diff_source_t *left_source, - /*const*/ apr_hash_t *left_props, - void *dir_baton, - const struct svn_diff_tree_processor_t *processor, - apr_pool_t *scratch_pool) -{ - diff_writer_info_t *dwi = processor->baton; - apr_array_header_t *prop_changes; - apr_hash_t *right_props; - - if (dwi->no_diff_deleted) - return SVN_NO_ERROR; - - right_props = apr_hash_make(scratch_pool); - SVN_ERR(svn_prop_diffs(&prop_changes, right_props, - left_props, scratch_pool)); - - SVN_ERR(diff_props_changed(relpath, - left_source->revision, - DIFF_REVNUM_NONEXISTENT, - prop_changes, - left_props, right_props, - TRUE /* show_diff_header */, - dwi, - scratch_pool)); - - return SVN_NO_ERROR; -} - -/*-----------------------------------------------------------------*/ - /** The logic behind 'svn diff' and 'svn merge'. */ @@ -1915,7 +544,7 @@ diff_wc_wc(const char *path1, All other options are the same as those passed to svn_client_diff7(). */ static svn_error_t * -diff_repos_repos(struct diff_driver_info_t *ddi, +diff_repos_repos(svn_client__diff_driver_info_t *ddi, const char *path_or_url1, const char *path_or_url2, const svn_opt_revision_t *revision1, @@ -2093,7 +722,7 @@ diff_repos_repos(struct diff_driver_info All other options are the same as those passed to svn_client_diff7(). */ static svn_error_t * -diff_repos_wc(struct diff_driver_info_t *ddi, +diff_repos_wc(svn_client__diff_driver_info_t *ddi, const char *path_or_url1, const svn_opt_revision_t *revision1, const svn_opt_revision_t *peg_revision1, @@ -2434,7 +1063,7 @@ diff_shelves(const apr_array_header_t *c /* This is basically just the guts of svn_client_diff[_summarize][_peg]6(). */ static svn_error_t * -do_diff(diff_driver_info_t *ddi, +do_diff(svn_client__diff_driver_info_t *ddi, const char *path_or_url1, const char *path_or_url2, const svn_opt_revision_t *revision1, @@ -2567,179 +1196,6 @@ do_diff(diff_driver_info_t *ddi, return SVN_NO_ERROR; } -/* Initialize DWI.diff_cmd and DWI.options, - * according to OPTIONS and CONFIG. CONFIG and OPTIONS may be null. - * Allocate the fields in RESULT_POOL, which should be at least as long-lived - * as the pool DWI itself is allocated in. - */ -static svn_error_t * -create_diff_writer_info(diff_writer_info_t *dwi, - const apr_array_header_t *options, - apr_hash_t *config, apr_pool_t *result_pool) -{ - const char *diff_cmd = NULL; - - /* See if there is a diff command and/or diff arguments. */ - if (config) - { - svn_config_t *cfg = svn_hash_gets(config, SVN_CONFIG_CATEGORY_CONFIG); - svn_config_get(cfg, &diff_cmd, SVN_CONFIG_SECTION_HELPERS, - SVN_CONFIG_OPTION_DIFF_CMD, NULL); - if (options == NULL) - { - const char *diff_extensions; - svn_config_get(cfg, &diff_extensions, SVN_CONFIG_SECTION_HELPERS, - SVN_CONFIG_OPTION_DIFF_EXTENSIONS, NULL); - if (diff_extensions) - options = svn_cstring_split(diff_extensions, " \t\n\r", TRUE, - result_pool); - } - } - - if (options == NULL) - options = apr_array_make(result_pool, 0, sizeof(const char *)); - - if (diff_cmd) - SVN_ERR(svn_path_cstring_to_utf8(&dwi->diff_cmd, diff_cmd, - result_pool)); - else - dwi->diff_cmd = NULL; - - /* If there was a command, arrange options to pass to it. */ - if (dwi->diff_cmd) - { - const char **argv = NULL; - int argc = options->nelts; - if (argc) - { - int i; - argv = apr_palloc(result_pool, argc * sizeof(char *)); - for (i = 0; i < argc; i++) - SVN_ERR(svn_utf_cstring_to_utf8(&argv[i], - APR_ARRAY_IDX(options, i, const char *), result_pool)); - } - dwi->options.for_external.argv = argv; - dwi->options.for_external.argc = argc; - } - else /* No command, so arrange options for internal invocation instead. */ - { - dwi->options.for_internal = svn_diff_file_options_create(result_pool); - SVN_ERR(svn_diff_file_options_parse(dwi->options.for_internal, - options, result_pool)); - } - - 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. ***/ @@ -2802,7 +1258,7 @@ svn_client_diff7(const apr_array_header_ { svn_opt_revision_t peg_revision; svn_diff_tree_processor_t *diff_processor; - struct diff_driver_info_t *ddi; + svn_client__diff_driver_info_t *ddi; if (ignore_properties && properties_only) return svn_error_create(SVN_ERR_INCORRECT_PARAMS, NULL, @@ -2816,20 +1272,23 @@ svn_client_diff7(const apr_array_header_ if (show_copies_as_adds || use_git_diff_format) ignore_ancestry = FALSE; - 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)); + SVN_ERR(svn_client__get_diff_writer_svn(&diff_processor, &ddi, + NULL /*anchor*/, + NULL /*orig_path_1*/, + NULL /*orig_path_2*/, + 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, @@ -2865,7 +1324,7 @@ svn_client_diff_peg7(const apr_array_hea apr_pool_t *pool) { svn_diff_tree_processor_t *diff_processor; - struct diff_driver_info_t *ddi; + svn_client__diff_driver_info_t *ddi; if (ignore_properties && properties_only) return svn_error_create(SVN_ERR_INCORRECT_PARAMS, NULL, @@ -2876,20 +1335,23 @@ svn_client_diff_peg7(const apr_array_hea if (show_copies_as_adds || use_git_diff_format) ignore_ancestry = FALSE; - 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)); + SVN_ERR(svn_client__get_diff_writer_svn(&diff_processor, &ddi, + NULL /*anchor*/, + NULL /*orig_path_1*/, + NULL /*orig_path_2*/, + 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,
Modified: subversion/branches/pristine-checksum-kind/subversion/libsvn_client/externals.c URL: http://svn.apache.org/viewvc/subversion/branches/pristine-checksum-kind/subversion/libsvn_client/externals.c?rev=1922345&r1=1922344&r2=1922345&view=diff ============================================================================== --- subversion/branches/pristine-checksum-kind/subversion/libsvn_client/externals.c (original) +++ subversion/branches/pristine-checksum-kind/subversion/libsvn_client/externals.c Fri Dec 6 13:59:05 2024 @@ -919,7 +919,7 @@ handle_external_item_change(svn_client_c SVN_ERR(switch_file_external(local_abspath, new_loc, - new_url, + new_loc->url, &new_item->peg_revision, &new_item->revision, parent_dir_abspath,
