You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by st...@apache.org on 2013/02/04 21:48:13 UTC
svn commit: r1442344 [6/39] - in /subversion/branches/fsfs-format7: ./
build/ build/ac-macros/ build/generator/ build/generator/templates/
build/win32/ contrib/client-side/emacs/
contrib/server-side/fsfsfixer/fixer/ contrib/server-side/svncutter/ doc/ ...
Modified: subversion/branches/fsfs-format7/subversion/libsvn_client/diff.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-format7/subversion/libsvn_client/diff.c?rev=1442344&r1=1442343&r2=1442344&view=diff
==============================================================================
--- subversion/branches/fsfs-format7/subversion/libsvn_client/diff.c (original)
+++ subversion/branches/fsfs-format7/subversion/libsvn_client/diff.c Mon Feb 4 20:48:05 2013
@@ -33,7 +33,6 @@
#include "svn_types.h"
#include "svn_hash.h"
#include "svn_wc.h"
-#include "svn_delta.h"
#include "svn_diff.h"
#include "svn_mergeinfo.h"
#include "svn_client.h"
@@ -46,8 +45,6 @@
#include "svn_pools.h"
#include "svn_config.h"
#include "svn_props.h"
-#include "svn_time.h"
-#include "svn_sorts.h"
#include "svn_subst.h"
#include "client.h"
@@ -65,154 +62,179 @@
_("Path '%s' must be an immediate child of " \
"the directory '%s'"), path, relative_to_dir)
-/* Adjust PATH to be relative to the repository root beneath ORIG_TARGET,
- * using RA_SESSION and WC_CTX, and return the result in *ADJUSTED_PATH.
- * ORIG_TARGET is one of the original targets passed to the diff command,
+/* Calculate the repository relative path of DIFF_RELPATH, using RA_SESSION
+ * 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.
- * WC_ROOT_ABSPATH is the absolute path to the root directory of a working
- * copy involved in a repos-wc diff, and may be NULL.
+ * ANCHOR is the local path where the diff editor is anchored.
* Do all allocations in POOL. */
static svn_error_t *
-adjust_relative_to_repos_root(const char **adjusted_path,
- const char *path,
- const char *orig_target,
- svn_ra_session_t *ra_session,
- svn_wc_context_t *wc_ctx,
- const char *wc_root_abspath,
- apr_pool_t *pool)
+make_repos_relpath(const char **repos_relpath,
+ const char *diff_relpath,
+ const char *orig_target,
+ svn_ra_session_t *ra_session,
+ svn_wc_context_t *wc_ctx,
+ const char *anchor,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
{
const char *local_abspath;
- const char *orig_relpath;
- const char *child_relpath;
+ const char *orig_repos_relpath = NULL;
- if (! ra_session)
+ if (! ra_session
+ || (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, path, pool));
- SVN_ERR(svn_wc__node_get_repos_relpath(adjusted_path, wc_ctx,
- local_abspath, pool, pool));
- return SVN_NO_ERROR;
- }
+ SVN_ERR(svn_dirent_get_absolute(&local_abspath,
+ svn_dirent_join(anchor, diff_relpath,
+ scratch_pool),
+ scratch_pool));
- /* Now deal with the repos-repos and repos-wc diff cases.
- * We need to make PATH appear as a child of ORIG_TARGET.
- * ORIG_TARGET is either a URL or a path to a working copy. First,
- * find out what ORIG_TARGET looks like relative to the repository root.*/
- if (svn_path_is_url(orig_target))
- SVN_ERR(svn_ra_get_path_relative_to_root(ra_session,
- &orig_relpath,
- orig_target, pool));
- else
- {
- const char *orig_abspath;
+ err = svn_wc__node_get_repos_relpath(repos_relpath, wc_ctx,
+ local_abspath,
+ result_pool, scratch_pool);
- SVN_ERR(svn_dirent_get_absolute(&orig_abspath, orig_target, pool));
- SVN_ERR(svn_wc__node_get_repos_relpath(&orig_relpath, wc_ctx,
- orig_abspath, pool, pool));
- }
+ if (!ra_session
+ || ! err
+ || (err && err->apr_err != SVN_ERR_WC_PATH_NOT_FOUND))
+ {
+ return svn_error_trace(err);
+ }
- /* PATH is either a child of the working copy involved in the diff (in
- * the repos-wc diff case), or it's a relative path we can readily use
- * (in either of the repos-repos and repos-wc diff cases). */
- child_relpath = NULL;
- if (wc_root_abspath)
- {
- SVN_ERR(svn_dirent_get_absolute(&local_abspath, path, pool));
- child_relpath = svn_dirent_is_child(wc_root_abspath, local_abspath, pool);
+ /* 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);
}
- if (child_relpath == NULL)
- child_relpath = path;
- *adjusted_path = svn_relpath_join(orig_relpath, child_relpath, pool);
+ {
+ const char *url;
+ const char *repos_root_url;
+
+ /* Would be nice if the RA layer could just provide the parent
+ repos_relpath of the ra session */
+ SVN_ERR(svn_ra_get_session_url(ra_session, &url, scratch_pool));
+
+ SVN_ERR(svn_ra_get_repos_root2(ra_session, &repos_root_url,
+ scratch_pool));
+
+ orig_repos_relpath = svn_uri_skip_ancestor(repos_root_url, url,
+ scratch_pool);
+
+ *repos_relpath = svn_relpath_join(orig_repos_relpath, diff_relpath,
+ result_pool);
+ }
return SVN_NO_ERROR;
}
-/* Adjust *PATH, *ORIG_PATH_1 and *ORIG_PATH_2, representing the changed file
- * and the two original targets passed to the diff command, to handle the
+/* 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. All
- * allocations are done in POOL. */
+ * 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. */
static svn_error_t *
-adjust_paths_for_diff_labels(const char **path,
+adjust_paths_for_diff_labels(const char **index_path,
const char **orig_path_1,
const char **orig_path_2,
const char *relative_to_dir,
- apr_pool_t *pool)
+ const char *anchor,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
{
- apr_size_t len;
- const char *new_path = *path;
+ const char *new_path = *index_path;
const char *new_path1 = *orig_path_1;
const char *new_path2 = *orig_path_2;
- /* ### Holy cow. Due to anchor/target weirdness, we can't
- simply join diff_cmd_baton->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. */
-
- len = strlen(svn_dirent_get_longest_ancestor(new_path1, new_path2, pool));
- new_path1 = new_path1 + len;
- new_path2 = 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_path1[0] == '\0')
- new_path1 = apr_psprintf(pool, "%s", new_path);
- else if (new_path1[0] == '/')
- new_path1 = apr_psprintf(pool, "%s\t(...%s)", new_path, new_path1);
- else
- new_path1 = apr_psprintf(pool, "%s\t(.../%s)", new_path, new_path1);
-
- if (new_path2[0] == '\0')
- new_path2 = apr_psprintf(pool, "%s", new_path);
- else if (new_path2[0] == '/')
- new_path2 = apr_psprintf(pool, "%s\t(...%s)", new_path, new_path2);
- else
- new_path2 = apr_psprintf(pool, "%s\t(.../%s)", new_path, new_path2);
+ 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,
- pool);
+ result_pool);
if (child_path)
new_path = child_path;
- else if (!svn_path_compare_paths(relative_to_dir, new_path))
+ else if (! strcmp(relative_to_dir, new_path))
new_path = ".";
else
return MAKE_ERR_BAD_RELATIVE_PATH(new_path, relative_to_dir);
- child_path = svn_dirent_is_child(relative_to_dir, new_path1, pool);
+ child_path = svn_dirent_is_child(relative_to_dir, new_path1,
+ result_pool);
+ }
- if (child_path)
- new_path1 = child_path;
- else if (!svn_path_compare_paths(relative_to_dir, new_path1))
- new_path1 = ".";
- else
- return MAKE_ERR_BAD_RELATIVE_PATH(new_path1, 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 diff_cmd_baton->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() */
+
+ 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.*/
- child_path = svn_dirent_is_child(relative_to_dir, new_path2, pool);
+ if (new_path[0] == '\0')
+ new_path = ".";
- if (child_path)
- new_path2 = child_path;
- else if (!svn_path_compare_paths(relative_to_dir, new_path2))
- new_path2 = ".";
- else
- return MAKE_ERR_BAD_RELATIVE_PATH(new_path2, relative_to_dir);
- }
- *path = 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_path1 = 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;
*orig_path_1 = new_path1;
*orig_path_2 = new_path2;
@@ -413,12 +435,12 @@ print_git_diff_header(svn_stream_t *os,
needed to normalize paths relative the repository root, and are ignored
if USE_GIT_DIFF_FORMAT is FALSE.
- WC_ROOT_ABSPATH is the absolute path to the root directory of a working
- copy involved in a repos-wc diff, and may be NULL. */
+ ANCHOR is the local path where the diff editor is anchored. */
static svn_error_t *
display_prop_diffs(const apr_array_header_t *propchanges,
apr_hash_t *original_props,
- const char *path,
+ const char *diff_relpath,
+ const char *anchor,
const char *orig_path1,
const char *orig_path2,
svn_revnum_t rev1,
@@ -430,75 +452,74 @@ display_prop_diffs(const apr_array_heade
svn_boolean_t use_git_diff_format,
svn_ra_session_t *ra_session,
svn_wc_context_t *wc_ctx,
- const char *wc_root_abspath,
- apr_pool_t *pool)
+ apr_pool_t *scratch_pool)
{
- const char *path1 = orig_path1;
- const char *path2 = orig_path2;
+ 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;
if (use_git_diff_format)
{
- SVN_ERR(adjust_relative_to_repos_root(&path1, path, orig_path1,
- ra_session, wc_ctx,
- wc_root_abspath,
- pool));
- SVN_ERR(adjust_relative_to_repos_root(&path2, path, orig_path2,
- ra_session, wc_ctx,
- wc_root_abspath,
- pool));
+ SVN_ERR(make_repos_relpath(&repos_relpath1, diff_relpath, orig_path1,
+ ra_session, wc_ctx, anchor,
+ scratch_pool, scratch_pool));
+ SVN_ERR(make_repos_relpath(&repos_relpath2, diff_relpath, orig_path2,
+ ra_session, wc_ctx, anchor,
+ scratch_pool, scratch_pool));
}
/* If we're creating a diff on the wc root, path would be empty. */
- if (path[0] == '\0')
- path = apr_psprintf(pool, ".");
+ SVN_ERR(adjust_paths_for_diff_labels(&index_path, &adjusted_path1,
+ &adjusted_path2,
+ relative_to_dir, anchor,
+ scratch_pool, scratch_pool));
if (show_diff_header)
{
const char *label1;
const char *label2;
- const char *adjusted_path1 = path1;
- const char *adjusted_path2 = path2;
-
- SVN_ERR(adjust_paths_for_diff_labels(&path, &adjusted_path1,
- &adjusted_path2,
- relative_to_dir, pool));
- label1 = diff_label(adjusted_path1, rev1, pool);
- label2 = diff_label(adjusted_path2, rev2, pool);
+ 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! */
- SVN_ERR(svn_stream_printf_from_utf8(outstream, encoding, pool,
+ SVN_ERR(svn_stream_printf_from_utf8(outstream, encoding, scratch_pool,
"Index: %s" APR_EOL_STR
SVN_DIFF__EQUAL_STRING APR_EOL_STR,
- path));
+ index_path));
if (use_git_diff_format)
SVN_ERR(print_git_diff_header(outstream, &label1, &label2,
svn_diff_op_modified,
- path1, path2, rev1, rev2, NULL,
+ repos_relpath1, repos_relpath2,
+ rev1, rev2, NULL,
SVN_INVALID_REVNUM,
- encoding, pool));
+ encoding, scratch_pool));
/* --- label1
* +++ label2 */
SVN_ERR(svn_diff__unidiff_write_header(
- outstream, encoding, label1, label2, pool));
+ outstream, encoding, label1, label2, scratch_pool));
}
- SVN_ERR(svn_stream_printf_from_utf8(outstream, encoding, pool,
+ SVN_ERR(svn_stream_printf_from_utf8(outstream, encoding, scratch_pool,
_("%sProperty changes on: %s%s"),
APR_EOL_STR,
- use_git_diff_format ? path1 : path,
+ use_git_diff_format
+ ? repos_relpath1
+ : index_path,
APR_EOL_STR));
- SVN_ERR(svn_stream_printf_from_utf8(outstream, encoding, pool,
+ 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, original_props,
- TRUE /* pretty_print_mergeinfo */, pool));
+ TRUE /* pretty_print_mergeinfo */, scratch_pool));
return SVN_NO_ERROR;
}
@@ -554,10 +575,6 @@ struct diff_cmd_baton {
/* Set this if you want diff output even for binary files. */
svn_boolean_t force_binary;
- /* Set this flag if you want diff_file_changed to output diffs
- unconditionally, even if the diffs are empty. */
- svn_boolean_t force_empty;
-
/* The directory that diff target paths should be considered as
relative to for output generation (see issue #2723). */
const char *relative_to_dir;
@@ -571,6 +588,9 @@ struct diff_cmd_baton {
/* 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;
@@ -579,48 +599,27 @@ struct diff_cmd_baton {
/* The RA session used during diffs involving the repository. */
svn_ra_session_t *ra_session;
- /* During a repos-wc diff, this is the absolute path to the root
- * directory of the working copy involved in the diff. */
- const char *wc_root_abspath;
-
/* The anchor to prefix before wc paths */
const char *anchor;
/* Whether the local diff target of a repos->wc diff is a copy. */
svn_boolean_t repos_wc_diff_target_is_copy;
-
- /* A hashtable using the visited paths as keys.
- * ### This is needed for us to know if we need to print a diff header for
- * ### a path that has property changes. */
- apr_hash_t *visited_paths;
};
-
-/* A helper function that marks a path as visited. It copies PATH
- * into the correct pool before referencing it from the hash table. */
-static void
-mark_path_as_visited(struct diff_cmd_baton *diff_cmd_baton, const char *path)
-{
- const char *p;
-
- p = apr_pstrdup(apr_hash_pool_get(diff_cmd_baton->visited_paths), path);
- apr_hash_set(diff_cmd_baton->visited_paths, p, APR_HASH_KEY_STRING, p);
-}
-
/* An helper for diff_dir_props_changed, diff_file_changed and diff_file_added
*/
static svn_error_t *
-diff_props_changed(svn_wc_notify_state_t *state,
- svn_boolean_t *tree_conflicted,
- const char *path,
+diff_props_changed(const char *diff_relpath,
+ svn_revnum_t rev1,
+ svn_revnum_t rev2,
svn_boolean_t dir_was_added,
const apr_array_header_t *propchanges,
apr_hash_t *original_props,
+ svn_boolean_t show_diff_header,
struct diff_cmd_baton *diff_cmd_baton,
apr_pool_t *scratch_pool)
{
apr_array_header_t *props;
- svn_boolean_t show_diff_header;
/* If property differences are ignored, there's nothing to do. */
if (diff_cmd_baton->ignore_properties)
@@ -629,21 +628,18 @@ diff_props_changed(svn_wc_notify_state_t
SVN_ERR(svn_categorize_props(propchanges, NULL, NULL, &props,
scratch_pool));
- if (apr_hash_get(diff_cmd_baton->visited_paths, path, APR_HASH_KEY_STRING))
- show_diff_header = FALSE;
- else
- show_diff_header = TRUE;
-
if (props->nelts > 0)
{
/* We're using the revnums from the diff_cmd_baton since there's
* no revision argument to the svn_wc_diff_callback_t
* dir_props_changed(). */
- SVN_ERR(display_prop_diffs(props, original_props, path,
+ SVN_ERR(display_prop_diffs(props, original_props,
+ diff_relpath,
+ diff_cmd_baton->anchor,
diff_cmd_baton->orig_path_1,
diff_cmd_baton->orig_path_2,
- diff_cmd_baton->revnum1,
- diff_cmd_baton->revnum2,
+ rev1,
+ rev2,
diff_cmd_baton->header_encoding,
diff_cmd_baton->outstream,
diff_cmd_baton->relative_to_dir,
@@ -651,20 +647,9 @@ diff_props_changed(svn_wc_notify_state_t
diff_cmd_baton->use_git_diff_format,
diff_cmd_baton->ra_session,
diff_cmd_baton->wc_ctx,
- diff_cmd_baton->wc_root_abspath,
scratch_pool));
-
- /* We've printed the diff header so now we can mark the path as
- * visited. */
- if (show_diff_header)
- mark_path_as_visited(diff_cmd_baton, path);
}
- if (state)
- *state = svn_wc_notify_state_unknown;
- if (tree_conflicted)
- *tree_conflicted = FALSE;
-
return SVN_NO_ERROR;
}
@@ -672,7 +657,7 @@ diff_props_changed(svn_wc_notify_state_t
static svn_error_t *
diff_dir_props_changed(svn_wc_notify_state_t *state,
svn_boolean_t *tree_conflicted,
- const char *path,
+ const char *diff_relpath,
svn_boolean_t dir_was_added,
const apr_array_header_t *propchanges,
apr_hash_t *original_props,
@@ -681,25 +666,31 @@ diff_dir_props_changed(svn_wc_notify_sta
{
struct diff_cmd_baton *diff_cmd_baton = diff_baton;
- if (diff_cmd_baton->anchor)
- path = svn_dirent_join(diff_cmd_baton->anchor, path, scratch_pool);
-
- return svn_error_trace(diff_props_changed(state,
- tree_conflicted, path,
+ return svn_error_trace(diff_props_changed(diff_relpath,
+ /* ### These revs be filled
+ * ### with per node info */
+ diff_cmd_baton->revnum1,
+ diff_cmd_baton->revnum2,
dir_was_added,
propchanges,
original_props,
+ TRUE /* show_diff_header */,
diff_cmd_baton,
scratch_pool));
}
-/* Show differences between TMPFILE1 and TMPFILE2. PATH, REV1, and REV2 are
- used in the headers to indicate the file and revisions. If either
+/* 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. */
+ but instead print a warning message.
+
+ 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(const char *path,
+diff_content_changed(svn_boolean_t *wrote_header,
+ const char *diff_relpath,
const char *tmpfile1,
const char *tmpfile2,
svn_revnum_t rev1,
@@ -707,17 +698,19 @@ diff_content_changed(const char *path,
const char *mimetype1,
const char *mimetype2,
svn_diff_operation_kind_t operation,
+ svn_boolean_t force_diff,
const char *copyfrom_path,
svn_revnum_t copyfrom_rev,
- struct diff_cmd_baton *diff_cmd_baton)
+ struct diff_cmd_baton *diff_cmd_baton,
+ apr_pool_t *scratch_pool)
{
int exitcode;
- apr_pool_t *subpool = svn_pool_create(diff_cmd_baton->pool);
const char *rel_to_dir = diff_cmd_baton->relative_to_dir;
svn_stream_t *errstream = diff_cmd_baton->errstream;
svn_stream_t *outstream = diff_cmd_baton->outstream;
const char *label1, *label2;
svn_boolean_t mt1_binary = FALSE, mt2_binary = FALSE;
+ const char *index_path = diff_relpath;
const char *path1 = diff_cmd_baton->orig_path_1;
const char *path2 = diff_cmd_baton->orig_path_2;
@@ -726,11 +719,12 @@ diff_content_changed(const char *path,
return SVN_NO_ERROR;
/* Generate the diff headers. */
- SVN_ERR(adjust_paths_for_diff_labels(&path, &path1, &path2,
- rel_to_dir, subpool));
+ SVN_ERR(adjust_paths_for_diff_labels(&index_path, &path1, &path2,
+ rel_to_dir, diff_cmd_baton->anchor,
+ scratch_pool, scratch_pool));
- label1 = diff_label(path1, rev1, subpool);
- label2 = diff_label(path2, rev2, subpool);
+ label1 = diff_label(path1, rev1, scratch_pool);
+ label2 = diff_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.
@@ -744,42 +738,41 @@ diff_content_changed(const char *path,
{
/* Print out the diff header. */
SVN_ERR(svn_stream_printf_from_utf8(outstream,
- diff_cmd_baton->header_encoding, subpool,
+ diff_cmd_baton->header_encoding, scratch_pool,
"Index: %s" APR_EOL_STR
SVN_DIFF__EQUAL_STRING APR_EOL_STR,
- path));
+ index_path));
/* ### Print git diff headers. */
SVN_ERR(svn_stream_printf_from_utf8(outstream,
- diff_cmd_baton->header_encoding, subpool,
+ diff_cmd_baton->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,
- diff_cmd_baton->header_encoding, subpool,
+ diff_cmd_baton->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,
- diff_cmd_baton->header_encoding, subpool,
+ diff_cmd_baton->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,
- diff_cmd_baton->header_encoding, subpool,
+ diff_cmd_baton->header_encoding, scratch_pool,
"svn:mime-type = %s" APR_EOL_STR,
mimetype1));
else
SVN_ERR(svn_stream_printf_from_utf8(outstream,
- diff_cmd_baton->header_encoding, subpool,
+ diff_cmd_baton->header_encoding, scratch_pool,
"svn:mime-type = (%s, %s)" APR_EOL_STR,
mimetype1, mimetype2));
}
/* Exit early. */
- svn_pool_destroy(subpool);
return SVN_NO_ERROR;
}
@@ -794,10 +787,10 @@ diff_content_changed(const char *path,
/* Print out the diff header. */
SVN_ERR(svn_stream_printf_from_utf8(outstream,
- diff_cmd_baton->header_encoding, subpool,
+ diff_cmd_baton->header_encoding, scratch_pool,
"Index: %s" APR_EOL_STR
SVN_DIFF__EQUAL_STRING APR_EOL_STR,
- path));
+ index_path));
/* ### 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
@@ -809,10 +802,10 @@ diff_content_changed(const char *path,
copy the contents to our stream. */
SVN_ERR(svn_io_open_unique_file3(&outfile, &outfilename, NULL,
svn_io_file_del_on_pool_cleanup,
- subpool, subpool));
+ scratch_pool, scratch_pool));
SVN_ERR(svn_io_open_unique_file3(&errfile, &errfilename, NULL,
svn_io_file_del_on_pool_cleanup,
- subpool, subpool));
+ scratch_pool, scratch_pool));
SVN_ERR(svn_io_run_diff2(".",
diff_cmd_baton->options.for_external.argv,
@@ -820,23 +813,25 @@ diff_content_changed(const char *path,
label1, label2,
tmpfile1, tmpfile2,
&exitcode, outfile, errfile,
- diff_cmd_baton->diff_cmd, subpool));
+ diff_cmd_baton->diff_cmd, scratch_pool));
- SVN_ERR(svn_io_file_close(outfile, subpool));
- SVN_ERR(svn_io_file_close(errfile, subpool));
+ SVN_ERR(svn_io_file_close(outfile, scratch_pool));
+ SVN_ERR(svn_io_file_close(errfile, scratch_pool));
/* Now, open and copy our files to our output streams. */
SVN_ERR(svn_stream_open_readonly(&stream, outfilename,
- subpool, subpool));
- SVN_ERR(svn_stream_copy3(stream, svn_stream_disown(outstream, subpool),
- NULL, NULL, subpool));
+ scratch_pool, scratch_pool));
+ SVN_ERR(svn_stream_copy3(stream, svn_stream_disown(outstream,
+ scratch_pool),
+ NULL, NULL, scratch_pool));
SVN_ERR(svn_stream_open_readonly(&stream, errfilename,
- subpool, subpool));
- SVN_ERR(svn_stream_copy3(stream, svn_stream_disown(errstream, subpool),
- NULL, NULL, subpool));
+ scratch_pool, scratch_pool));
+ SVN_ERR(svn_stream_copy3(stream, svn_stream_disown(errstream,
+ scratch_pool),
+ NULL, NULL, scratch_pool));
/* We have a printed a diff for this path, mark it as visited. */
- mark_path_as_visited(diff_cmd_baton, path);
+ *wrote_header = TRUE;
}
else /* use libsvn_diff to generate the diff */
{
@@ -844,48 +839,55 @@ diff_content_changed(const char *path,
SVN_ERR(svn_diff_file_diff_2(&diff, tmpfile1, tmpfile2,
diff_cmd_baton->options.for_internal,
- subpool));
+ scratch_pool));
- if (svn_diff_contains_diffs(diff) || diff_cmd_baton->force_empty ||
- diff_cmd_baton->use_git_diff_format)
+ if (force_diff
+ || diff_cmd_baton->use_git_diff_format
+ || svn_diff_contains_diffs(diff))
{
/* Print out the diff header. */
SVN_ERR(svn_stream_printf_from_utf8(outstream,
- diff_cmd_baton->header_encoding, subpool,
+ diff_cmd_baton->header_encoding, scratch_pool,
"Index: %s" APR_EOL_STR
SVN_DIFF__EQUAL_STRING APR_EOL_STR,
- path));
+ index_path));
if (diff_cmd_baton->use_git_diff_format)
{
- const char *tmp_path1, *tmp_path2;
- SVN_ERR(adjust_relative_to_repos_root(
- &tmp_path1, path, diff_cmd_baton->orig_path_1,
- diff_cmd_baton->ra_session, diff_cmd_baton->wc_ctx,
- diff_cmd_baton->wc_root_abspath, subpool));
- SVN_ERR(adjust_relative_to_repos_root(
- &tmp_path2, path, diff_cmd_baton->orig_path_2,
- diff_cmd_baton->ra_session, diff_cmd_baton->wc_ctx,
- diff_cmd_baton->wc_root_abspath, subpool));
+ const char *repos_relpath1;
+ const char *repos_relpath2;
+ SVN_ERR(make_repos_relpath(&repos_relpath1, diff_relpath,
+ diff_cmd_baton->orig_path_1,
+ diff_cmd_baton->ra_session,
+ diff_cmd_baton->wc_ctx,
+ diff_cmd_baton->anchor,
+ scratch_pool, scratch_pool));
+ SVN_ERR(make_repos_relpath(&repos_relpath2, diff_relpath,
+ diff_cmd_baton->orig_path_2,
+ diff_cmd_baton->ra_session,
+ diff_cmd_baton->wc_ctx,
+ diff_cmd_baton->anchor,
+ scratch_pool, scratch_pool));
SVN_ERR(print_git_diff_header(outstream, &label1, &label2,
operation,
- tmp_path1, tmp_path2, rev1, rev2,
+ repos_relpath1, repos_relpath2,
+ rev1, rev2,
copyfrom_path,
copyfrom_rev,
diff_cmd_baton->header_encoding,
- subpool));
+ scratch_pool));
}
/* Output the actual diff */
- if (svn_diff_contains_diffs(diff) || diff_cmd_baton->force_empty)
+ if (force_diff || svn_diff_contains_diffs(diff))
SVN_ERR(svn_diff_file_output_unified3(outstream, diff,
tmpfile1, tmpfile2, label1, label2,
diff_cmd_baton->header_encoding, rel_to_dir,
diff_cmd_baton->options.for_internal->show_c_function,
- subpool));
+ scratch_pool));
/* We have a printed a diff for this path, mark it as visited. */
- mark_path_as_visited(diff_cmd_baton, path);
+ *wrote_header = TRUE;
}
}
@@ -893,16 +895,13 @@ diff_content_changed(const char *path,
to need to write a diff plug-in mechanism that makes use of the
two paths, instead of just blindly running SVN_CLIENT_DIFF. */
- /* Destroy the subpool. */
- svn_pool_destroy(subpool);
-
return SVN_NO_ERROR;
}
static svn_error_t *
diff_file_opened(svn_boolean_t *tree_conflicted,
svn_boolean_t *skip,
- const char *path,
+ const char *diff_relpath,
svn_revnum_t rev,
void *diff_baton,
apr_pool_t *scratch_pool)
@@ -915,7 +914,7 @@ static svn_error_t *
diff_file_changed(svn_wc_notify_state_t *content_state,
svn_wc_notify_state_t *prop_state,
svn_boolean_t *tree_conflicted,
- const char *path,
+ const char *diff_relpath,
const char *tmpfile1,
const char *tmpfile2,
svn_revnum_t rev1,
@@ -928,6 +927,7 @@ diff_file_changed(svn_wc_notify_state_t
apr_pool_t *scratch_pool)
{
struct diff_cmd_baton *diff_cmd_baton = diff_baton;
+ svn_boolean_t wrote_header = FALSE;
/* During repos->wc diff of a copy revision numbers obtained
* from the working copy are always SVN_INVALID_REVNUM. */
@@ -942,24 +942,18 @@ diff_file_changed(svn_wc_notify_state_t
rev2 = diff_cmd_baton->revnum2;
}
- if (diff_cmd_baton->anchor)
- path = svn_dirent_join(diff_cmd_baton->anchor, path, scratch_pool);
if (tmpfile1)
- SVN_ERR(diff_content_changed(path,
+ SVN_ERR(diff_content_changed(&wrote_header, diff_relpath,
tmpfile1, tmpfile2, rev1, rev2,
- mimetype1, mimetype2,
- svn_diff_op_modified, NULL,
- SVN_INVALID_REVNUM, diff_cmd_baton));
+ mimetype1, mimetype2,
+ svn_diff_op_modified, FALSE,
+ NULL,
+ SVN_INVALID_REVNUM, diff_cmd_baton,
+ scratch_pool));
if (prop_changes->nelts > 0)
- SVN_ERR(diff_props_changed(prop_state, tree_conflicted,
- path, FALSE, prop_changes,
- original_props, diff_cmd_baton, scratch_pool));
- if (content_state)
- *content_state = svn_wc_notify_state_unknown;
- if (prop_state)
- *prop_state = svn_wc_notify_state_unknown;
- if (tree_conflicted)
- *tree_conflicted = FALSE;
+ SVN_ERR(diff_props_changed(diff_relpath, rev1, rev2, FALSE, prop_changes,
+ original_props, !wrote_header,
+ diff_cmd_baton, scratch_pool));
return SVN_NO_ERROR;
}
@@ -972,7 +966,7 @@ static svn_error_t *
diff_file_added(svn_wc_notify_state_t *content_state,
svn_wc_notify_state_t *prop_state,
svn_boolean_t *tree_conflicted,
- const char *path,
+ const char *diff_relpath,
const char *tmpfile1,
const char *tmpfile2,
svn_revnum_t rev1,
@@ -987,6 +981,7 @@ diff_file_added(svn_wc_notify_state_t *c
apr_pool_t *scratch_pool)
{
struct diff_cmd_baton *diff_cmd_baton = diff_baton;
+ svn_boolean_t wrote_header = FALSE;
/* During repos->wc diff of a copy revision numbers obtained
* from the working copy are always SVN_INVALID_REVNUM. */
@@ -1001,40 +996,44 @@ diff_file_added(svn_wc_notify_state_t *c
rev2 = diff_cmd_baton->revnum2;
}
- if (diff_cmd_baton->anchor)
- path = svn_dirent_join(diff_cmd_baton->anchor, path, scratch_pool);
+ if (diff_cmd_baton->no_diff_added)
+ {
+ const char *index_path = diff_relpath;
- /* We want diff_file_changed to unconditionally show diffs, even if
- the diff is empty (as would be the case if an empty file were
- added.) It's important, because 'patch' would still see an empty
- diff and create an empty file. It's also important to let the
- user see that *something* happened. */
- diff_cmd_baton->force_empty = TRUE;
+ if (diff_cmd_baton->anchor)
+ index_path = svn_dirent_join(diff_cmd_baton->anchor, diff_relpath,
+ scratch_pool);
- if (tmpfile1 && copyfrom_path)
- SVN_ERR(diff_content_changed(path,
+ SVN_ERR(svn_stream_printf_from_utf8(diff_cmd_baton->outstream,
+ diff_cmd_baton->header_encoding, scratch_pool,
+ "Index: %s (added)" APR_EOL_STR
+ SVN_DIFF__EQUAL_STRING APR_EOL_STR,
+ index_path));
+ wrote_header = TRUE;
+ }
+ else if (tmpfile1 && copyfrom_path)
+ SVN_ERR(diff_content_changed(&wrote_header, diff_relpath,
tmpfile1, tmpfile2, rev1, rev2,
mimetype1, mimetype2,
- svn_diff_op_copied, copyfrom_path,
- copyfrom_revision, diff_cmd_baton));
+ svn_diff_op_copied,
+ TRUE /* force diff output */,
+ copyfrom_path,
+ copyfrom_revision, diff_cmd_baton,
+ scratch_pool));
else if (tmpfile1)
- SVN_ERR(diff_content_changed(path,
+ SVN_ERR(diff_content_changed(&wrote_header, diff_relpath,
tmpfile1, tmpfile2, rev1, rev2,
mimetype1, mimetype2,
- svn_diff_op_added, NULL, SVN_INVALID_REVNUM,
- diff_cmd_baton));
- if (prop_changes->nelts > 0)
- SVN_ERR(diff_props_changed(prop_state, tree_conflicted,
- path, FALSE, prop_changes,
- original_props, diff_cmd_baton, scratch_pool));
- if (content_state)
- *content_state = svn_wc_notify_state_unknown;
- if (prop_state)
- *prop_state = svn_wc_notify_state_unknown;
- if (tree_conflicted)
- *tree_conflicted = FALSE;
+ svn_diff_op_added,
+ TRUE /* force diff output */,
+ NULL, SVN_INVALID_REVNUM,
+ diff_cmd_baton, scratch_pool));
- diff_cmd_baton->force_empty = FALSE;
+ if (prop_changes->nelts > 0)
+ SVN_ERR(diff_props_changed(diff_relpath, rev1, rev2,
+ FALSE, prop_changes,
+ original_props, ! wrote_header,
+ diff_cmd_baton, scratch_pool));
return SVN_NO_ERROR;
}
@@ -1043,7 +1042,7 @@ diff_file_added(svn_wc_notify_state_t *c
static svn_error_t *
diff_file_deleted(svn_wc_notify_state_t *state,
svn_boolean_t *tree_conflicted,
- const char *path,
+ const char *diff_relpath,
const char *tmpfile1,
const char *tmpfile2,
const char *mimetype1,
@@ -1054,36 +1053,39 @@ diff_file_deleted(svn_wc_notify_state_t
{
struct diff_cmd_baton *diff_cmd_baton = diff_baton;
- if (diff_cmd_baton->anchor)
- path = svn_dirent_join(diff_cmd_baton->anchor, path, scratch_pool);
-
if (diff_cmd_baton->no_diff_deleted)
{
+ const char *index_path = diff_relpath;
+
+ if (diff_cmd_baton->anchor)
+ index_path = svn_dirent_join(diff_cmd_baton->anchor, diff_relpath,
+ scratch_pool);
+
SVN_ERR(svn_stream_printf_from_utf8(diff_cmd_baton->outstream,
diff_cmd_baton->header_encoding, scratch_pool,
"Index: %s (deleted)" APR_EOL_STR
SVN_DIFF__EQUAL_STRING APR_EOL_STR,
- path));
+ index_path));
}
else
{
+ svn_boolean_t wrote_header = FALSE;
if (tmpfile1)
- SVN_ERR(diff_content_changed(path,
+ SVN_ERR(diff_content_changed(&wrote_header, diff_relpath,
tmpfile1, tmpfile2,
diff_cmd_baton->revnum1,
diff_cmd_baton->revnum2,
mimetype1, mimetype2,
- svn_diff_op_deleted, NULL,
- SVN_INVALID_REVNUM, diff_cmd_baton));
+ svn_diff_op_deleted, FALSE,
+ NULL, SVN_INVALID_REVNUM,
+ diff_cmd_baton,
+ scratch_pool));
+
+ /* Should we also report the properties as deleted? */
}
/* We don't list all the deleted properties. */
- if (state)
- *state = svn_wc_notify_state_unknown;
- if (tree_conflicted)
- *tree_conflicted = FALSE;
-
return SVN_NO_ERROR;
}
@@ -1093,17 +1095,13 @@ diff_dir_added(svn_wc_notify_state_t *st
svn_boolean_t *tree_conflicted,
svn_boolean_t *skip,
svn_boolean_t *skip_children,
- const char *path,
+ const char *diff_relpath,
svn_revnum_t rev,
const char *copyfrom_path,
svn_revnum_t copyfrom_revision,
void *diff_baton,
apr_pool_t *scratch_pool)
{
- /*struct diff_cmd_baton *diff_cmd_baton = diff_baton;
- if (diff_cmd_baton->anchor)
- path = svn_dirent_join(diff_cmd_baton->anchor, path, scratch_pool);*/
-
/* Do nothing. */
return SVN_NO_ERROR;
@@ -1113,14 +1111,10 @@ diff_dir_added(svn_wc_notify_state_t *st
static svn_error_t *
diff_dir_deleted(svn_wc_notify_state_t *state,
svn_boolean_t *tree_conflicted,
- const char *path,
+ const char *diff_relpath,
void *diff_baton,
apr_pool_t *scratch_pool)
{
- /*struct diff_cmd_baton *diff_cmd_baton = diff_baton;
- if (diff_cmd_baton->anchor)
- path = svn_dirent_join(diff_cmd_baton->anchor, path, scratch_pool);*/
-
/* Do nothing. */
return SVN_NO_ERROR;
@@ -1131,15 +1125,11 @@ static svn_error_t *
diff_dir_opened(svn_boolean_t *tree_conflicted,
svn_boolean_t *skip,
svn_boolean_t *skip_children,
- const char *path,
+ const char *diff_relpath,
svn_revnum_t rev,
void *diff_baton,
apr_pool_t *scratch_pool)
{
- /*struct diff_cmd_baton *diff_cmd_baton = diff_baton;
- if (diff_cmd_baton->anchor)
- path = svn_dirent_join(diff_cmd_baton->anchor, path, scratch_pool);*/
-
/* Do nothing. */
return SVN_NO_ERROR;
@@ -1150,15 +1140,11 @@ static svn_error_t *
diff_dir_closed(svn_wc_notify_state_t *contentstate,
svn_wc_notify_state_t *propstate,
svn_boolean_t *tree_conflicted,
- const char *path,
+ const char *diff_relpath,
svn_boolean_t dir_was_added,
void *diff_baton,
apr_pool_t *scratch_pool)
{
- /*struct diff_cmd_baton *diff_cmd_baton = diff_baton;
- if (diff_cmd_baton->anchor)
- path = svn_dirent_join(diff_cmd_baton->anchor, path, scratch_pool);*/
-
/* Do nothing. */
return SVN_NO_ERROR;
@@ -1540,9 +1526,13 @@ diff_prepare_repos_repos(const char **ur
- svn_client__get_diff_editor: compares some URL1@REV1 vs. URL2@REV2
+ Since Subversion 1.8 we also have a variant of svn_wc_diff called
+ svn_client__arbitrary_nodes_diff, that allows handling WORKING-WORKING
+ comparisions between nodes in the working copy.
+
So the truth of the matter is, if the caller's arguments can't be
- pigeonholed into one of these three use-cases, we currently bail
- with a friendly apology.
+ 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()
perfectly general. For now, we live with the 90% case. Certainly,
@@ -1561,479 +1551,6 @@ unsupported_diff_error(svn_error_t *chil
"that is not yet supported"));
}
-/* Try to get properties for LOCAL_ABSPATH and return them in the property
- * hash *PROPS. If there are no properties because LOCAL_ABSPATH is not
- * versioned, return an empty property hash. */
-static svn_error_t *
-get_props(apr_hash_t **props,
- const char *local_abspath,
- svn_wc_context_t *wc_ctx,
- apr_pool_t *result_pool,
- apr_pool_t *scratch_pool)
-{
- svn_error_t *err;
-
- err = svn_wc_prop_list2(props, wc_ctx, local_abspath, result_pool,
- scratch_pool);
- if (err)
- {
- if (err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND ||
- err->apr_err == SVN_ERR_WC_NOT_WORKING_COPY ||
- err->apr_err == SVN_ERR_WC_UPGRADE_REQUIRED)
- {
- svn_error_clear(err);
- *props = apr_hash_make(result_pool);
- }
- else
- return svn_error_trace(err);
- }
-
- return SVN_NO_ERROR;
-}
-
-/* Produce a diff between two arbitrary files at LOCAL_ABSPATH1 and
- * LOCAL_ABSPATH2, using the diff callbacks from CALLBACKS.
- * Use PATH as the name passed to diff callbacks.
- * FILE1_IS_EMPTY and FILE2_IS_EMPTY are used as hints which diff callback
- * function to use to compare the files (added/deleted/changed).
- *
- * If ORIGINAL_PROPS_OVERRIDE is not NULL, use it as original properties
- * instead of reading properties from LOCAL_ABSPATH1. This is required when
- * a file replaces a directory, where LOCAL_ABSPATH1 is an empty file that
- * file content must be diffed against, but properties to diff against come
- * from the replaced directory. */
-static svn_error_t *
-do_arbitrary_files_diff(const char *local_abspath1,
- const char *local_abspath2,
- const char *path,
- svn_boolean_t file1_is_empty,
- svn_boolean_t file2_is_empty,
- apr_hash_t *original_props_override,
- const svn_wc_diff_callbacks4_t *callbacks,
- struct diff_cmd_baton *diff_cmd_baton,
- svn_client_ctx_t *ctx,
- apr_pool_t *scratch_pool)
-{
- apr_hash_t *original_props;
- apr_hash_t *modified_props;
- apr_array_header_t *prop_changes;
- svn_string_t *original_mime_type = NULL;
- svn_string_t *modified_mime_type = NULL;
-
- if (ctx->cancel_func)
- SVN_ERR(ctx->cancel_func(ctx->cancel_baton));
-
- if (diff_cmd_baton->ignore_properties)
- {
- original_props = apr_hash_make(scratch_pool);
- modified_props = apr_hash_make(scratch_pool);
- }
- else
- {
- /* Try to get properties from either file. It's OK if the files do not
- * have properties, or if they are unversioned. */
- if (original_props_override)
- original_props = original_props_override;
- else
- SVN_ERR(get_props(&original_props, local_abspath1, ctx->wc_ctx,
- scratch_pool, scratch_pool));
- SVN_ERR(get_props(&modified_props, local_abspath2, ctx->wc_ctx,
- scratch_pool, scratch_pool));
- }
-
- SVN_ERR(svn_prop_diffs(&prop_changes, modified_props, original_props,
- scratch_pool));
-
- if (!diff_cmd_baton->force_binary)
- {
- /* Try to determine the mime-type of each file. */
- original_mime_type = apr_hash_get(original_props, SVN_PROP_MIME_TYPE,
- APR_HASH_KEY_STRING);
- if (!file1_is_empty && !original_mime_type)
- {
- const char *mime_type;
- SVN_ERR(svn_io_detect_mimetype2(&mime_type, local_abspath1,
- ctx->mimetypes_map, scratch_pool));
-
- if (mime_type)
- original_mime_type = svn_string_create(mime_type, scratch_pool);
- }
-
- modified_mime_type = apr_hash_get(modified_props, SVN_PROP_MIME_TYPE,
- APR_HASH_KEY_STRING);
- if (!file2_is_empty && !modified_mime_type)
- {
- const char *mime_type;
- SVN_ERR(svn_io_detect_mimetype2(&mime_type, local_abspath1,
- ctx->mimetypes_map, scratch_pool));
-
- if (mime_type)
- modified_mime_type = svn_string_create(mime_type, scratch_pool);
- }
- }
-
- /* Produce the diff. */
- if (file1_is_empty && !file2_is_empty)
- SVN_ERR(callbacks->file_added(NULL, NULL, NULL, path,
- local_abspath1, local_abspath2,
- /* ### TODO get real revision info
- * for versioned files? */
- SVN_INVALID_REVNUM, SVN_INVALID_REVNUM,
- original_mime_type ?
- original_mime_type->data : NULL,
- modified_mime_type ?
- modified_mime_type->data : NULL,
- /* ### TODO get copyfrom? */
- NULL, SVN_INVALID_REVNUM,
- prop_changes, original_props,
- diff_cmd_baton, scratch_pool));
- else if (!file1_is_empty && file2_is_empty)
- SVN_ERR(callbacks->file_deleted(NULL, NULL, path,
- local_abspath1, local_abspath2,
- original_mime_type ?
- original_mime_type->data : NULL,
- modified_mime_type ?
- modified_mime_type->data : NULL,
- original_props,
- diff_cmd_baton, scratch_pool));
- else
- SVN_ERR(callbacks->file_changed(NULL, NULL, NULL, path,
- local_abspath1, local_abspath2,
- /* ### TODO get real revision info
- * for versioned files? */
- SVN_INVALID_REVNUM, SVN_INVALID_REVNUM,
- original_mime_type ?
- original_mime_type->data : NULL,
- modified_mime_type ?
- modified_mime_type->data : NULL,
- prop_changes, original_props,
- diff_cmd_baton, scratch_pool));
-
- return SVN_NO_ERROR;
-}
-
-struct arbitrary_diff_walker_baton {
- /* The root directories of the trees being compared. */
- const char *root1_abspath;
- const char *root2_abspath;
-
- /* TRUE if recursing within an added subtree of root2_abspath that
- * does not exist in root1_abspath. */
- svn_boolean_t recursing_within_added_subtree;
-
- /* TRUE if recursing within an administrative (.i.e. .svn) directory. */
- svn_boolean_t recursing_within_adm_dir;
-
- /* The absolute path of the adm dir if RECURSING_WITHIN_ADM_DIR is TRUE.
- * Else this is NULL.*/
- const char *adm_dir_abspath;
-
- /* A path to an empty file used for diffs that add/delete files. */
- const char *empty_file_abspath;
-
- const svn_wc_diff_callbacks4_t *callbacks;
- struct diff_cmd_baton *callback_baton;
- svn_client_ctx_t *ctx;
- apr_pool_t *pool;
-} arbitrary_diff_walker_baton;
-
-/* Forward declaration needed because this function has a cyclic
- * dependency with do_arbitrary_dirs_diff(). */
-static svn_error_t *
-arbitrary_diff_walker(void *baton, const char *local_abspath,
- const apr_finfo_t *finfo,
- apr_pool_t *scratch_pool);
-
-/* Produce a diff between two arbitrary directories at LOCAL_ABSPATH1 and
- * LOCAL_ABSPATH2, using the provided diff callbacks to show file changes
- * and, for versioned nodes, property changes.
- *
- * If ROOT_ABSPATH1 and ROOT_ABSPATH2 are not NULL, show paths in diffs
- * relative to these roots, rather than relative to LOCAL_ABSPATH1 and
- * LOCAL_ABSPATH2. This is needed when crawling a subtree that exists
- * only within LOCAL_ABSPATH2. */
-static svn_error_t *
-do_arbitrary_dirs_diff(const char *local_abspath1,
- const char *local_abspath2,
- const char *root_abspath1,
- const char *root_abspath2,
- const svn_wc_diff_callbacks4_t *callbacks,
- struct diff_cmd_baton *callback_baton,
- svn_client_ctx_t *ctx,
- apr_pool_t *scratch_pool)
-{
- apr_file_t *empty_file;
- svn_node_kind_t kind1;
-
- struct arbitrary_diff_walker_baton b;
-
- /* If LOCAL_ABSPATH1 is not a directory, crawl LOCAL_ABSPATH2 instead
- * and compare it to LOCAL_ABSPATH1, showing only additions.
- * This case can only happen during recursion from arbitrary_diff_walker(),
- * because do_arbitrary_nodes_diff() prevents this from happening at
- * the root of the comparison. */
- SVN_ERR(svn_io_check_resolved_path(local_abspath1, &kind1, scratch_pool));
- b.recursing_within_added_subtree = (kind1 != svn_node_dir);
-
- b.root1_abspath = root_abspath1 ? root_abspath1 : local_abspath1;
- b.root2_abspath = root_abspath2 ? root_abspath2 : local_abspath2;
- b.recursing_within_adm_dir = FALSE;
- b.adm_dir_abspath = NULL;
- b.callbacks = callbacks;
- b.callback_baton = callback_baton;
- b.ctx = ctx;
- b.pool = scratch_pool;
-
- SVN_ERR(svn_io_open_unique_file3(&empty_file, &b.empty_file_abspath,
- NULL, svn_io_file_del_on_pool_cleanup,
- scratch_pool, scratch_pool));
-
- SVN_ERR(svn_io_dir_walk2(b.recursing_within_added_subtree ? local_abspath2
- : local_abspath1,
- 0, arbitrary_diff_walker, &b, scratch_pool));
-
- return SVN_NO_ERROR;
-}
-
-/* An implementation of svn_io_walk_func_t.
- * Note: LOCAL_ABSPATH is the path being crawled and can be on either side
- * of the diff depending on baton->recursing_within_added_subtree. */
-static svn_error_t *
-arbitrary_diff_walker(void *baton, const char *local_abspath,
- const apr_finfo_t *finfo,
- apr_pool_t *scratch_pool)
-{
- struct arbitrary_diff_walker_baton *b = baton;
- const char *local_abspath1;
- const char *local_abspath2;
- svn_node_kind_t kind1;
- svn_node_kind_t kind2;
- const char *child_relpath;
- apr_hash_t *dirents1;
- apr_hash_t *dirents2;
- apr_hash_t *merged_dirents;
- apr_array_header_t *sorted_dirents;
- int i;
- apr_pool_t *iterpool;
-
- if (b->ctx->cancel_func)
- SVN_ERR(b->ctx->cancel_func(b->ctx->cancel_baton));
-
- if (finfo->filetype != APR_DIR)
- return SVN_NO_ERROR;
-
- if (b->recursing_within_adm_dir)
- {
- if (svn_dirent_skip_ancestor(b->adm_dir_abspath, local_abspath))
- return SVN_NO_ERROR;
- else
- {
- b->recursing_within_adm_dir = FALSE;
- b->adm_dir_abspath = NULL;
- }
- }
- else if (strcmp(svn_dirent_basename(local_abspath, scratch_pool),
- SVN_WC_ADM_DIR_NAME) == 0)
- {
- b->recursing_within_adm_dir = TRUE;
- b->adm_dir_abspath = apr_pstrdup(b->pool, local_abspath);
- return SVN_NO_ERROR;
- }
-
- if (b->recursing_within_added_subtree)
- child_relpath = svn_dirent_skip_ancestor(b->root2_abspath, local_abspath);
- else
- child_relpath = svn_dirent_skip_ancestor(b->root1_abspath, local_abspath);
- if (!child_relpath)
- return SVN_NO_ERROR;
-
- local_abspath1 = svn_dirent_join(b->root1_abspath, child_relpath,
- scratch_pool);
- SVN_ERR(svn_io_check_resolved_path(local_abspath1, &kind1, scratch_pool));
-
- local_abspath2 = svn_dirent_join(b->root2_abspath, child_relpath,
- scratch_pool);
- SVN_ERR(svn_io_check_resolved_path(local_abspath2, &kind2, scratch_pool));
-
- if (kind1 == svn_node_dir)
- SVN_ERR(svn_io_get_dirents3(&dirents1, local_abspath1,
- TRUE, /* only_check_type */
- scratch_pool, scratch_pool));
- else
- dirents1 = apr_hash_make(scratch_pool);
-
- if (kind2 == svn_node_dir)
- {
- apr_hash_t *original_props;
- apr_hash_t *modified_props;
- apr_array_header_t *prop_changes;
-
- /* Show any property changes for this directory. */
- SVN_ERR(get_props(&original_props, local_abspath1, b->ctx->wc_ctx,
- scratch_pool, scratch_pool));
- SVN_ERR(get_props(&modified_props, local_abspath2, b->ctx->wc_ctx,
- scratch_pool, scratch_pool));
- SVN_ERR(svn_prop_diffs(&prop_changes, modified_props, original_props,
- scratch_pool));
- if (prop_changes->nelts > 0)
- SVN_ERR(diff_props_changed(NULL, NULL, child_relpath,
- b->recursing_within_added_subtree,
- prop_changes, original_props,
- b->callback_baton, scratch_pool));
-
- /* Read directory entries. */
- SVN_ERR(svn_io_get_dirents3(&dirents2, local_abspath2,
- TRUE, /* only_check_type */
- scratch_pool, scratch_pool));
- }
- else
- dirents2 = apr_hash_make(scratch_pool);
-
- /* Compare dirents1 to dirents2 and show added/deleted/changed files. */
- merged_dirents = apr_hash_merge(scratch_pool, dirents1, dirents2,
- NULL, NULL);
- sorted_dirents = svn_sort__hash(merged_dirents,
- svn_sort_compare_items_as_paths,
- scratch_pool);
- iterpool = svn_pool_create(scratch_pool);
- for (i = 0; i < sorted_dirents->nelts; i++)
- {
- svn_sort__item_t elt = APR_ARRAY_IDX(sorted_dirents, i, svn_sort__item_t);
- const char *name = elt.key;
- svn_io_dirent2_t *dirent1;
- svn_io_dirent2_t *dirent2;
- const char *child1_abspath;
- const char *child2_abspath;
-
- svn_pool_clear(iterpool);
-
- if (b->ctx->cancel_func)
- SVN_ERR(b->ctx->cancel_func(b->ctx->cancel_baton));
-
- if (strcmp(name, SVN_WC_ADM_DIR_NAME) == 0)
- continue;
-
- dirent1 = apr_hash_get(dirents1, name, APR_HASH_KEY_STRING);
- if (!dirent1)
- {
- dirent1 = svn_io_dirent2_create(iterpool);
- dirent1->kind = svn_node_none;
- }
- dirent2 = apr_hash_get(dirents2, name, APR_HASH_KEY_STRING);
- if (!dirent2)
- {
- dirent2 = svn_io_dirent2_create(iterpool);
- dirent2->kind = svn_node_none;
- }
-
- child1_abspath = svn_dirent_join(local_abspath1, name, iterpool);
- child2_abspath = svn_dirent_join(local_abspath2, name, iterpool);
-
- if (dirent1->special)
- SVN_ERR(svn_io_check_resolved_path(child1_abspath, &dirent1->kind,
- iterpool));
- if (dirent2->special)
- SVN_ERR(svn_io_check_resolved_path(child1_abspath, &dirent2->kind,
- iterpool));
-
- if (dirent1->kind == svn_node_dir &&
- dirent2->kind == svn_node_dir)
- continue;
-
- /* Files that exist only in dirents1. */
- if (dirent1->kind == svn_node_file &&
- (dirent2->kind == svn_node_dir || dirent2->kind == svn_node_none))
- SVN_ERR(do_arbitrary_files_diff(child1_abspath, b->empty_file_abspath,
- svn_relpath_join(child_relpath, name,
- iterpool),
- FALSE, TRUE, NULL,
- b->callbacks, b->callback_baton,
- b->ctx, iterpool));
-
- /* Files that exist only in dirents2. */
- if (dirent2->kind == svn_node_file &&
- (dirent1->kind == svn_node_dir || dirent1->kind == svn_node_none))
- {
- apr_hash_t *original_props;
-
- SVN_ERR(get_props(&original_props, child1_abspath, b->ctx->wc_ctx,
- scratch_pool, scratch_pool));
- SVN_ERR(do_arbitrary_files_diff(b->empty_file_abspath, child2_abspath,
- svn_relpath_join(child_relpath, name,
- iterpool),
- TRUE, FALSE, original_props,
- b->callbacks, b->callback_baton,
- b->ctx, iterpool));
- }
-
- /* Files that exist in dirents1 and dirents2. */
- if (dirent1->kind == svn_node_file && dirent2->kind == svn_node_file)
- SVN_ERR(do_arbitrary_files_diff(child1_abspath, child2_abspath,
- svn_relpath_join(child_relpath, name,
- iterpool),
- FALSE, FALSE, NULL,
- b->callbacks, b->callback_baton,
- b->ctx, scratch_pool));
-
- /* Directories that only exist in dirents2. These aren't crawled
- * by this walker so we have to crawl them separately. */
- if (dirent2->kind == svn_node_dir &&
- (dirent1->kind == svn_node_file || dirent1->kind == svn_node_none))
- SVN_ERR(do_arbitrary_dirs_diff(child1_abspath, child2_abspath,
- b->root1_abspath, b->root2_abspath,
- b->callbacks, b->callback_baton,
- b->ctx, iterpool));
- }
-
- svn_pool_destroy(iterpool);
-
- return SVN_NO_ERROR;
-}
-
-/* Produce a diff between two files or two directories at LOCAL_ABSPATH1
- * and LOCAL_ABSPATH2, using the provided diff callbacks to show changes
- * in files. The files and directories involved may be part of a working
- * copy or they may be unversioned. For versioned files, show property
- * changes, too. */
-static svn_error_t *
-do_arbitrary_nodes_diff(const char *local_abspath1,
- const char *local_abspath2,
- const svn_wc_diff_callbacks4_t *callbacks,
- struct diff_cmd_baton *callback_baton,
- svn_client_ctx_t *ctx,
- apr_pool_t *scratch_pool)
-{
- svn_node_kind_t kind1;
- svn_node_kind_t kind2;
-
- SVN_ERR(svn_io_check_resolved_path(local_abspath1, &kind1, scratch_pool));
- SVN_ERR(svn_io_check_resolved_path(local_abspath2, &kind2, scratch_pool));
- if (kind1 != kind2)
- return svn_error_createf(SVN_ERR_NODE_UNEXPECTED_KIND, NULL,
- _("'%s' is not the same node kind as '%s'"),
- local_abspath1, local_abspath2);
-
- if (kind1 == svn_node_file)
- SVN_ERR(do_arbitrary_files_diff(local_abspath1, local_abspath2,
- svn_dirent_basename(local_abspath2,
- scratch_pool),
- FALSE, FALSE, NULL,
- callbacks, callback_baton,
- ctx, scratch_pool));
- else if (kind1 == svn_node_dir)
- SVN_ERR(do_arbitrary_dirs_diff(local_abspath1, local_abspath2,
- NULL, NULL,
- callbacks, callback_baton,
- ctx, scratch_pool));
- else
- return svn_error_createf(SVN_ERR_NODE_UNEXPECTED_KIND, NULL,
- _("'%s' is not a file or directory"),
- kind1 == svn_node_none ?
- local_abspath1 : local_abspath2);
- return SVN_NO_ERROR;
-}
-
-
/* Perform a diff between two working-copy paths.
PATH1 and PATH2 are both working copy paths. REVISION1 and
@@ -2064,18 +1581,17 @@ diff_wc_wc(const char *path1,
SVN_ERR(svn_dirent_get_absolute(&abspath1, path1, pool));
+ /* Currently we support only the case where path1 and path2 are the
+ same path. */
if ((strcmp(path1, path2) != 0)
|| (! ((revision1->kind == svn_opt_revision_base)
&& (revision2->kind == svn_opt_revision_working))))
- {
- const char *abspath2;
+ 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"
+ )));
- SVN_ERR(svn_dirent_get_absolute(&abspath2, path2, pool));
- return svn_error_trace(do_arbitrary_nodes_diff(abspath1, abspath2,
- callbacks,
- callback_baton,
- ctx, pool));
- }
/* Resolve named revisions to real numbers. */
err = svn_client__get_revision_number(&callback_baton->revnum1, NULL,
@@ -2438,6 +1954,8 @@ diff_repos_repos(const svn_wc_diff_callb
const svn_delta_editor_t *diff_editor;
void *diff_edit_baton;
+ const svn_diff_tree_processor_t *diff_processor;
+
const char *url1;
const char *url2;
const char *base_path;
@@ -2494,14 +2012,19 @@ diff_repos_repos(const svn_wc_diff_callb
/* Set up the repos_diff editor on BASE_PATH, if available.
Otherwise, we just use "". */
- SVN_ERR(svn_client__get_diff_editor(
+
+ SVN_ERR(svn_wc__wrap_diff_callbacks(&diff_processor,
+ callbacks, callback_baton,
+ TRUE /* walk_deleted_dirs */,
+ pool, pool));
+
+ SVN_ERR(svn_client__get_diff_editor2(
&diff_editor, &diff_edit_baton,
- depth,
- extra_ra_session, rev1, TRUE /* walk_deleted_dirs */,
+ extra_ra_session, depth,
+ rev1,
TRUE /* text_deltas */,
- callbacks, callback_baton,
+ diff_processor,
ctx->cancel_func, ctx->cancel_baton,
- NULL /* no notify_func */, NULL /* no notify_baton */,
pool));
/* We want to switch our txn into URL2 */
@@ -2699,7 +2222,8 @@ diff_repos_wc(const char *path_or_url1,
svn_boolean_t use_git_diff_format,
const apr_array_header_t *changelists,
const svn_wc_diff_callbacks4_t *callbacks,
- struct diff_cmd_baton *callback_baton,
+ void *callback_baton,
+ struct diff_cmd_baton *cmd_baton,
svn_client_ctx_t *ctx,
apr_pool_t *pool)
{
@@ -2760,25 +2284,18 @@ diff_repos_wc(const char *path_or_url1,
ctx, pool));
if (!reverse)
{
- callback_baton->orig_path_1 = url1;
- callback_baton->orig_path_2 =
+ cmd_baton->orig_path_1 = url1;
+ cmd_baton->orig_path_2 =
svn_path_url_add_component2(anchor_url, target, pool);
}
else
{
- callback_baton->orig_path_1 =
+ cmd_baton->orig_path_1 =
svn_path_url_add_component2(anchor_url, target, pool);
- callback_baton->orig_path_2 = url1;
+ cmd_baton->orig_path_2 = url1;
}
}
- if (use_git_diff_format)
- {
- SVN_ERR(svn_wc__get_wc_root(&callback_baton->wc_root_abspath,
- ctx->wc_ctx, anchor_abspath,
- pool, pool));
- }
-
/* Open an RA session to URL1 to figure out its node kind. */
SVN_ERR(svn_client__open_ra_session_internal(&ra_session, NULL, url1,
NULL, NULL, FALSE, TRUE,
@@ -2793,13 +2310,13 @@ diff_repos_wc(const char *path_or_url1,
/* Figure out the node kind of the local target. */
SVN_ERR(svn_io_check_resolved_path(abspath2, &kind2, pool));
- callback_baton->ra_session = ra_session;
- callback_baton->anchor = anchor;
+ cmd_baton->ra_session = ra_session;
+ cmd_baton->anchor = anchor;
if (!reverse)
- callback_baton->revnum1 = rev;
+ cmd_baton->revnum1 = rev;
else
- callback_baton->revnum2 = rev;
+ cmd_baton->revnum2 = rev;
/* Check if our diff target is a copied node. */
SVN_ERR(svn_wc__node_get_origin(&is_copy,
@@ -2860,8 +2377,8 @@ diff_repos_wc(const char *path_or_url1,
const char *copyfrom_basename;
svn_depth_t copy_depth;
- callback_baton->repos_wc_diff_target_is_copy = TRUE;
-
+ cmd_baton->repos_wc_diff_target_is_copy = TRUE;
+
/* We're diffing a locally copied/moved directory.
* Describe the copy source to the reporter instead of the copy itself.
* Doing the latter would generate a single add_directory() call to the
@@ -2964,7 +2481,8 @@ do_diff(const svn_wc_diff_callbacks4_t *
path_or_url2, revision2, FALSE, depth,
ignore_ancestry, show_copies_as_adds,
use_git_diff_format, changelists,
- callbacks, callback_baton, ctx, pool));
+ callbacks, callback_baton, callback_baton,
+ ctx, pool));
}
}
else /* path_or_url1 is a working copy path */
@@ -2975,20 +2493,85 @@ do_diff(const svn_wc_diff_callbacks4_t *
path_or_url1, revision1, TRUE, depth,
ignore_ancestry, show_copies_as_adds,
use_git_diff_format, changelists,
- callbacks, callback_baton, ctx, pool));
+ callbacks, callback_baton, callback_baton,
+ ctx, pool));
}
else /* path_or_url2 is a working copy path */
{
- SVN_ERR(diff_wc_wc(path_or_url1, revision1, path_or_url2, revision2,
- depth, ignore_ancestry, show_copies_as_adds,
- use_git_diff_format, changelists,
- callbacks, callback_baton, ctx, pool));
+ if (revision1->kind == svn_opt_revision_working
+ && revision2->kind == svn_opt_revision_working)
+ {
+ const char *abspath1;
+ const char *abspath2;
+
+ SVN_ERR(svn_dirent_get_absolute(&abspath1, path_or_url1, pool));
+ SVN_ERR(svn_dirent_get_absolute(&abspath2, path_or_url2, pool));
+
+ SVN_ERR(svn_client__arbitrary_nodes_diff(abspath1, abspath2,
+ callbacks,
+ callback_baton,
+ ctx, pool));
+ }
+ else
+ SVN_ERR(diff_wc_wc(path_or_url1, revision1,
+ path_or_url2, revision2,
+ depth, ignore_ancestry, show_copies_as_adds,
+ use_git_diff_format, changelists,
+ callbacks, callback_baton, ctx, pool));
}
}
return SVN_NO_ERROR;
}
+/* Perform a diff between a repository path and a working-copy path.
+
+ PATH_OR_URL1 may be either a URL or a working copy path. PATH2 is a
+ working copy path. REVISION1 and REVISION2 are their respective
+ revisions. If REVERSE is TRUE, the diff will be done in reverse.
+ If PEG_REVISION is specified, then PATH_OR_URL1 is the path in the peg
+ revision, and the actual repository path to be compared is
+ determined by following copy history.
+
+ All other options are the same as those passed to svn_client_diff6(). */
+static svn_error_t *
+diff_summarize_repos_wc(svn_client_diff_summarize_func_t summarize_func,
+ void *summarize_baton,
+ const char *path_or_url1,
+ const svn_opt_revision_t *revision1,
+ const svn_opt_revision_t *peg_revision,
+ const char *path2,
+ const svn_opt_revision_t *revision2,
+ svn_boolean_t reverse,
+ svn_depth_t depth,
+ svn_boolean_t ignore_ancestry,
+ const apr_array_header_t *changelists,
+ svn_client_ctx_t *ctx,
+ apr_pool_t *pool)
+{
+ const char *anchor, *target;
+ svn_wc_diff_callbacks4_t *callbacks;
+ void *callback_baton;
+ struct diff_cmd_baton cmd_baton;
+
+ SVN_ERR_ASSERT(! svn_path_is_url(path2));
+
+ SVN_ERR(svn_wc_get_actual_target2(&anchor, &target,
+ ctx->wc_ctx, path2,
+ pool, pool));
+
+ SVN_ERR(svn_client__get_diff_summarize_callbacks(
+ &callbacks, &callback_baton, target, reverse,
+ summarize_func, summarize_baton, pool));
+
+ SVN_ERR(diff_repos_wc(path_or_url1, revision1, peg_revision,
+ path2, revision2, reverse,
+ depth, FALSE, TRUE, FALSE, changelists,
+ callbacks, callback_baton, &cmd_baton,
+ ctx, pool));
+ return SVN_NO_ERROR;
+}
+
/* Perform a summary diff between two working-copy paths.
PATH1 and PATH2 are both working copy paths. REVISION1 and
@@ -3033,7 +2616,7 @@ diff_summarize_wc_wc(svn_client_diff_sum
SVN_ERR(svn_wc_read_kind(&kind, ctx->wc_ctx, abspath1, FALSE, pool));
target1 = (kind == svn_node_dir) ? "" : svn_dirent_basename(path1, pool);
SVN_ERR(svn_client__get_diff_summarize_callbacks(
- &callbacks, &callback_baton, target1,
+ &callbacks, &callback_baton, target1, FALSE,
summarize_func, summarize_baton, pool));
SVN_ERR(svn_wc_diff6(ctx->wc_ctx,
@@ -3069,6 +2652,8 @@ diff_summarize_repos_repos(svn_client_di
const svn_delta_editor_t *diff_editor;
void *diff_edit_baton;
+ const svn_diff_tree_processor_t *diff_processor;
+
const char *url1;
const char *url2;
const char *base_path;
@@ -3098,7 +2683,7 @@ diff_summarize_repos_repos(svn_client_di
* Walk the tree that does exist, showing a series of additions
* or deletions. */
SVN_ERR(svn_client__get_diff_summarize_callbacks(
- &callbacks, &callback_baton, target1,
+ &callbacks, &callback_baton, target1, FALSE,
summarize_func, summarize_baton, pool));
SVN_ERR(diff_repos_repos_added_or_deleted_target(target1, target2,
rev1, rev2,
@@ -3112,7 +2697,7 @@ diff_summarize_repos_repos(svn_client_di
SVN_ERR(svn_client__get_diff_summarize_callbacks(
&callbacks, &callback_baton,
- target1, summarize_func, summarize_baton, pool));
+ target1, FALSE, summarize_func, summarize_baton, pool));
/* Now, we open an extra RA session to the correct anchor
location for URL1. This is used to get the kind of deleted paths. */
@@ -3121,13 +2706,20 @@ diff_summarize_repos_repos(svn_client_di
TRUE, ctx, pool));
/* Set up the repos_diff editor. */
- SVN_ERR(svn_client__get_diff_editor(&diff_editor, &diff_edit_baton,
- depth,
- extra_ra_session, rev1, TRUE /* walk_deleted_dirs */,
- FALSE /* text_deltas */,
- callbacks, callback_baton,
- ctx->cancel_func, ctx->cancel_baton,
- NULL /* notify_func */, NULL /* notify_baton */, pool));
+
+ SVN_ERR(svn_wc__wrap_diff_callbacks(&diff_processor,
+ callbacks, callback_baton,
+ TRUE /* walk_deleted_dirs */,
+ pool, pool));
+
+ SVN_ERR(svn_client__get_diff_editor2(&diff_editor, &diff_edit_baton,
+ extra_ra_session,
+ depth,
+ rev1,
+ FALSE /* text_deltas */,
+ diff_processor,
+ ctx->cancel_func, ctx->cancel_baton,
+ pool));
/* We want to switch our txn into URL2 */
SVN_ERR(svn_ra_do_diff3
@@ -3165,23 +2757,76 @@ do_diff_summarize(svn_client_diff_summar
SVN_ERR(check_paths(&is_repos1, &is_repos2, path_or_url1, path_or_url2,
revision1, revision2, peg_revision));
- if (is_repos1 && is_repos2)
- return diff_summarize_repos_repos(summarize_func, summarize_baton, ctx,
- path_or_url1, path_or_url2,
- revision1, revision2,
- peg_revision, depth, ignore_ancestry,
- pool);
- else if (! is_repos1 && ! is_repos2)
- return diff_summarize_wc_wc(summarize_func, summarize_baton,
- path_or_url1, revision1,
- path_or_url2, revision2,
- depth, ignore_ancestry,
- changelists, ctx, pool);
- else
- return unsupported_diff_error(
- svn_error_create(SVN_ERR_UNSUPPORTED_FEATURE, NULL,
- _("Summarizing diff cannot compare repository "
- "to WC")));
+ if (is_repos1)
+ {
+ if (is_repos2)
+ SVN_ERR(diff_summarize_repos_repos(summarize_func, summarize_baton, ctx,
+ path_or_url1, path_or_url2,
+ revision1, revision2,
+ peg_revision, depth, ignore_ancestry,
+ pool));
+ else
+ SVN_ERR(diff_summarize_repos_wc(summarize_func, summarize_baton,
+ path_or_url1, revision1,
+ peg_revision,
+ path_or_url2, revision2,
+ FALSE, depth,
+ ignore_ancestry,
+ changelists,
+ ctx, pool));
+ }
+ else /* ! is_repos1 */
+ {
+ if (is_repos2)
+ SVN_ERR(diff_summarize_repos_wc(summarize_func, summarize_baton,
+ path_or_url2, revision2,
+ peg_revision,
+ path_or_url1, revision1,
+ TRUE, depth,
+ ignore_ancestry,
+ changelists,
+ ctx, pool));
+ else
+ {
+ if (revision1->kind == svn_opt_revision_working
+ && revision2->kind == svn_opt_revision_working)
+ {
+ const char *abspath1;
+ const char *abspath2;
+ svn_wc_diff_callbacks4_t *callbacks;
+ void *callback_baton;
+ const char *target;
+ svn_node_kind_t kind;
+
+ SVN_ERR(svn_dirent_get_absolute(&abspath1, path_or_url1, pool));
+ SVN_ERR(svn_dirent_get_absolute(&abspath2, path_or_url2, pool));
+
+ SVN_ERR(svn_io_check_resolved_path(abspath1, &kind, pool));
+
+ if (kind == svn_node_dir)
+ target = "";
+ else
+ target = svn_dirent_basename(path_or_url1, NULL);
+
+ SVN_ERR(svn_client__get_diff_summarize_callbacks(
+ &callbacks, &callback_baton, target, FALSE,
+ summarize_func, summarize_baton, pool));
+
+ SVN_ERR(svn_client__arbitrary_nodes_diff(abspath1, abspath2,
+ callbacks,
+ callback_baton,
+ ctx, pool));
+ }
+ else
+ SVN_ERR(diff_summarize_wc_wc(summarize_func, summarize_baton,
+ path_or_url1, revision1,
+ path_or_url2, revision2,
+ depth, ignore_ancestry,
+ changelists, ctx, pool));
+ }
+ }
+
+ return SVN_NO_ERROR;
}
@@ -3295,6 +2940,7 @@ svn_client_diff6(const apr_array_header_
const char *relative_to_dir,
svn_depth_t depth,
svn_boolean_t ignore_ancestry,
+ 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,
@@ -3332,17 +2978,15 @@ svn_client_diff6(const apr_array_header_
diff_cmd_baton.revnum1 = SVN_INVALID_REVNUM;
diff_cmd_baton.revnum2 = SVN_INVALID_REVNUM;
- diff_cmd_baton.force_empty = FALSE;
diff_cmd_baton.force_binary = ignore_content_type;
diff_cmd_baton.ignore_properties = ignore_properties;
diff_cmd_baton.properties_only = properties_only;
diff_cmd_baton.relative_to_dir = relative_to_dir;
diff_cmd_baton.use_git_diff_format = use_git_diff_format;
+ diff_cmd_baton.no_diff_added = no_diff_added;
diff_cmd_baton.no_diff_deleted = no_diff_deleted;
diff_cmd_baton.wc_ctx = ctx->wc_ctx;
- diff_cmd_baton.visited_paths = apr_hash_make(pool);
diff_cmd_baton.ra_session = NULL;
- diff_cmd_baton.wc_root_abspath = NULL;
diff_cmd_baton.anchor = NULL;
return do_diff(&diff_callbacks, &diff_cmd_baton, ctx,
@@ -3361,6 +3005,7 @@ svn_client_diff_peg6(const apr_array_hea
const char *relative_to_dir,
svn_depth_t depth,
svn_boolean_t ignore_ancestry,
+ 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,
@@ -3394,17 +3039,15 @@ svn_client_diff_peg6(const apr_array_hea
diff_cmd_baton.revnum1 = SVN_INVALID_REVNUM;
diff_cmd_baton.revnum2 = SVN_INVALID_REVNUM;
- diff_cmd_baton.force_empty = FALSE;
diff_cmd_baton.force_binary = ignore_content_type;
diff_cmd_baton.ignore_properties = ignore_properties;
diff_cmd_baton.properties_only = properties_only;
diff_cmd_baton.relative_to_dir = relative_to_dir;
diff_cmd_baton.use_git_diff_format = use_git_diff_format;
+ diff_cmd_baton.no_diff_added = no_diff_added;
diff_cmd_baton.no_diff_deleted = no_diff_deleted;
diff_cmd_baton.wc_ctx = ctx->wc_ctx;
- diff_cmd_baton.visited_paths = apr_hash_make(pool);
diff_cmd_baton.ra_session = NULL;
- diff_cmd_baton.wc_root_abspath = NULL;
diff_cmd_baton.anchor = NULL;
return do_diff(&diff_callbacks, &diff_cmd_baton, ctx,