Author: julianfoad
Date: Mon Aug 22 11:11:50 2011
New Revision: 1160204
URL: http://svn.apache.org/viewvc?rev=1160204&view=rev
Log:
Extend 'svn diff --summarize' to support WC-WC diffs. Before this it only
supported repo-repo diffs.
* subversion/libsvn_client/diff.c
(diff_summarize_wc_wc): New function.
(do_diff_summarize): Call it. Update the error message. Accept a
'changelists' parameter and use it for these WC-WC diffs.
(svn_client_diff_summarize2, svn_client_diff_summarize_peg2): Pass the
'changelists' parameter, which was previously unused, to
do_diff_summarize().
* subversion/libsvn_wc/diff_local.c
(diff_status_callback): Call the dir_added, dir_deleted, dir_opened and
dir_closed callbacks at the appropriate times.
* subversion/tests/cmdline/diff_tests.py
(diff_summarize_xml): Test a WC-WC diff instead of checking that such a
request would fail.
* subversion/tests/cmdline/input_validation_tests.py
(invalid_diff_targets): Don't expect a WC-WC summarizing diff to fail.
Modified:
subversion/trunk/subversion/libsvn_client/diff.c
subversion/trunk/subversion/libsvn_wc/diff_local.c
subversion/trunk/subversion/tests/cmdline/diff_tests.py
subversion/trunk/subversion/tests/cmdline/input_validation_tests.py
Modified: subversion/trunk/subversion/libsvn_client/diff.c
URL:
http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_client/diff.c?rev=1160204&r1=1160203&r2=1160204&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_client/diff.c (original)
+++ subversion/trunk/subversion/libsvn_client/diff.c Mon Aug 22 11:11:50 2011
@@ -2007,6 +2007,73 @@ do_diff(const svn_wc_diff_callbacks4_t *
return SVN_NO_ERROR;
}
+/* Perform a summary diff between two working-copy paths.
+
+ PATH1 and PATH2 are both working copy paths. REVISION1 and
+ REVISION2 are their respective revisions.
+
+ All other options are the same as those passed to svn_client_diff5(). */
+static svn_error_t *
+diff_summarize_wc_wc(svn_client_diff_summarize_func_t summarize_func,
+ void *summarize_baton,
+ const char *path1,
+ const svn_opt_revision_t *revision1,
+ const char *path2,
+ const svn_opt_revision_t *revision2,
+ svn_depth_t depth,
+ svn_boolean_t ignore_ancestry,
+ svn_boolean_t use_git_diff_format,
+ const apr_array_header_t *changelists,
+ svn_client_ctx_t *ctx,
+ apr_pool_t *pool)
+{
+ svn_wc_diff_callbacks4_t *callbacks;
+ void *callback_baton;
+ const char *abspath1, *anchor1, *target1;
+ svn_node_kind_t kind;
+
+ SVN_ERR_ASSERT(! svn_path_is_url(path1));
+ SVN_ERR_ASSERT(! svn_path_is_url(path2));
+
+ /* 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))))
+ 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")));
+
+ /* Find the node kind of PATH1 so that we know whether the diff drive will
+ be anchored at PATH1 or its parent dir. */
+ SVN_ERR(svn_dirent_get_absolute(&abspath1, path1, pool));
+ SVN_ERR(svn_wc_read_kind(&kind, ctx->wc_ctx, abspath1, FALSE, pool));
+ if (kind == svn_node_dir)
+ {
+ anchor1 = path1;
+ target1 = "";
+ }
+ else
+ {
+ svn_dirent_split(&anchor1, &target1, path1, pool);
+ }
+ SVN_ERR(svn_client__get_diff_summarize_callbacks(
+ &callbacks, &callback_baton, target1,
+ summarize_func, summarize_baton, pool));
+
+ SVN_ERR(svn_wc_diff6(ctx->wc_ctx,
+ abspath1,
+ callbacks, callback_baton,
+ depth,
+ ignore_ancestry, FALSE /* show_copies_as_adds */,
+ /* FALSE */ use_git_diff_format, changelists,
+ ctx->cancel_func, ctx->cancel_baton,
+ pool));
+ return SVN_NO_ERROR;
+}
+
/* Perform a diff summary between two repository paths. */
static svn_error_t *
diff_summarize_repos_repos(svn_client_diff_summarize_func_t summarize_func,
@@ -2094,6 +2161,7 @@ do_diff_summarize(svn_client_diff_summar
const svn_opt_revision_t *peg_revision,
svn_depth_t depth,
svn_boolean_t ignore_ancestry,
+ const apr_array_header_t *changelists,
apr_pool_t *pool)
{
svn_boolean_t is_repos1;
@@ -2108,10 +2176,17 @@ do_diff_summarize(svn_client_diff_summar
path1, path2, revision1, revision2,
peg_revision, depth, ignore_ancestry,
pool);
+ else if (! is_repos1 && ! is_repos2)
+ return diff_summarize_wc_wc(summarize_func, summarize_baton,
+ path1, revision1, path2, revision2,
+ depth, ignore_ancestry,
+ FALSE /* use_git_diff_format */,
+ changelists, ctx, pool);
else
- return svn_error_create(SVN_ERR_UNSUPPORTED_FEATURE, NULL,
- _("Summarizing diff can only compare repository "
- "to repository"));
+ return unsupported_diff_error(
+ svn_error_create(SVN_ERR_UNSUPPORTED_FEATURE, NULL,
+ _("Summarizing diff cannot compare repository "
+ "to WC")));
}
@@ -2341,10 +2416,9 @@ svn_client_diff_summarize2(const char *p
svn_opt_revision_t peg_revision;
peg_revision.kind = svn_opt_revision_unspecified;
- /* ### CHANGELISTS parameter isn't used */
return do_diff_summarize(summarize_func, summarize_baton, ctx,
path1, path2, revision1, revision2, &peg_revision,
- depth, ignore_ancestry, pool);
+ depth, ignore_ancestry, changelists, pool);
}
svn_error_t *
@@ -2360,10 +2434,10 @@ svn_client_diff_summarize_peg2(const cha
svn_client_ctx_t *ctx,
apr_pool_t *pool)
{
- /* ### CHANGELISTS parameter isn't used */
return do_diff_summarize(summarize_func, summarize_baton, ctx,
path, path, start_revision, end_revision,
- peg_revision, depth, ignore_ancestry, pool);
+ peg_revision,
+ depth, ignore_ancestry, changelists, pool);
}
svn_client_diff_summarize_t *
Modified: subversion/trunk/subversion/libsvn_wc/diff_local.c
URL:
http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_wc/diff_local.c?rev=1160204&r1=1160203&r2=1160204&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_wc/diff_local.c (original)
+++ subversion/trunk/subversion/libsvn_wc/diff_local.c Mon Aug 22 11:11:50 2011
@@ -474,8 +474,29 @@ diff_status_callback(void *baton,
SVN_ERR(file_diff(eb, local_abspath, path, scratch_pool));
}
}
- else
+ else /* it's a directory */
{
+ const char *path = svn_dirent_skip_ancestor(eb->anchor_abspath,
+ local_abspath);
+
+ /* Report the directory as deleted and/or opened or added. */
+ if (status->node_status == svn_wc_status_deleted
+ || status->node_status == svn_wc_status_replaced)
+ SVN_ERR(eb->callbacks->dir_deleted(NULL, NULL, path,
+ eb->callback_baton, scratch_pool));
+
+ if (status->node_status == svn_wc_status_added
+ || status->node_status == svn_wc_status_replaced)
+ SVN_ERR(eb->callbacks->dir_added(NULL, NULL, NULL, NULL,
+ path, status->revision,
+ path, status->revision /* ### ? */,
+ eb->callback_baton, scratch_pool));
+ else
+ SVN_ERR(eb->callbacks->dir_opened(NULL, NULL, NULL,
+ path, status->revision,
+ eb->callback_baton, scratch_pool));
+
+ /* Report the prop change. */
/* ### This case should probably be extended for git-diff, but this
is what the old diff code provided */
if (status->node_status == svn_wc_status_deleted
@@ -484,9 +505,6 @@ diff_status_callback(void *baton,
{
apr_array_header_t *propchanges;
apr_hash_t *baseprops;
- const char *path = svn_dirent_skip_ancestor(eb->anchor_abspath,
- local_abspath);
-
SVN_ERR(svn_wc__internal_propdiff(&propchanges, &baseprops,
eb->db, local_abspath,
@@ -498,6 +516,15 @@ diff_status_callback(void *baton,
eb->callback_baton,
scratch_pool));
}
+
+ /* Close the dir.
+ * ### This should be done after all children have been processed, not
+ * yet. The current Subversion-internal callers don't care. */
+ SVN_ERR(eb->callbacks->dir_closed(
+ NULL, NULL, NULL, path,
+ (status->node_status == svn_wc_status_added
+ || status->node_status == svn_wc_status_replaced),
+ eb->callback_baton, scratch_pool));
}
return SVN_NO_ERROR;
}
Modified: subversion/trunk/subversion/tests/cmdline/diff_tests.py
URL:
http://svn.apache.org/viewvc/subversion/trunk/subversion/tests/cmdline/diff_tests.py?rev=1160204&r1=1160203&r2=1160204&view=diff
==============================================================================
--- subversion/trunk/subversion/tests/cmdline/diff_tests.py (original)
+++ subversion/trunk/subversion/tests/cmdline/diff_tests.py Mon Aug 22 11:11:50
2011
@@ -3184,6 +3184,16 @@ def diff_summarize_xml(sbox):
wc_rev=2)
expected_status.remove("A/B/lambda")
+ # 3) Test working copy summarize
+ paths = ['A/mu', 'iota', 'A/D/G/tau', 'newfile', 'A/B/lambda',
+ 'newdir',]
+ items = ['modified', 'none', 'modified', 'added', 'deleted', 'added',]
+ kinds = ['file','file','file','file','file', 'dir',]
+ props = ['none', 'modified', 'modified', 'none', 'none', 'none',]
+
+ svntest.actions.run_and_verify_diff_summarize_xml(
+ [], wc_dir, paths, items, props, kinds, wc_dir)
+
svntest.actions.run_and_verify_commit(wc_dir, expected_output,
expected_status, None, wc_dir)
@@ -3197,38 +3207,21 @@ def diff_summarize_xml(sbox):
".*No such revision 5555555",
None, wc_dir, None, None, None, '-r0:5555555', wc_dir)
- # 3) Test working copy summarize
- svntest.actions.run_and_verify_diff_summarize_xml(
- ".*Summarizing diff can only compare repository to repository",
- None, wc_dir, None, None, wc_dir)
-
# 4) Test --summarize --xml on -c2
- paths = ['iota',]
- items = ['none',]
- kinds = ['file',]
- props = ['modified',]
+ paths_iota = ['iota',]
+ items_iota = ['none',]
+ kinds_iota = ['file',]
+ props_iota = ['modified',]
svntest.actions.run_and_verify_diff_summarize_xml(
- [], wc_dir, paths, items, props, kinds, '-c2',
+ [], wc_dir, paths_iota, items_iota, props_iota, kinds_iota, '-c2',
os.path.join(wc_dir, 'iota'))
# 5) Test --summarize --xml on -r1:2
- paths = ['A/mu', 'iota', 'A/D/G/tau', 'newfile', 'A/B/lambda',
- 'newdir',]
- items = ['modified', 'none', 'modified', 'added', 'deleted', 'added',]
- kinds = ['file','file','file','file','file', 'dir',]
- props = ['none', 'modified', 'modified', 'none', 'none', 'none',]
-
svntest.actions.run_and_verify_diff_summarize_xml(
[], wc_dir, paths, items, props, kinds, '-r1:2', wc_dir)
# 6) Same as test #5 but ran against a URL instead of a WC path
- paths = ['A/mu', 'iota', 'A/D/G/tau', 'newfile', 'A/B/lambda',
- 'newdir',]
- items = ['modified', 'none', 'modified', 'added', 'deleted', 'added',]
- kinds = ['file','file','file','file','file', 'dir',]
- props = ['none', 'modified', 'modified', 'none', 'none', 'none',]
-
svntest.actions.run_and_verify_diff_summarize_xml(
[], sbox.repo_url, paths, items, props, kinds, '-r1:2', sbox.repo_url)
Modified: subversion/trunk/subversion/tests/cmdline/input_validation_tests.py
URL:
http://svn.apache.org/viewvc/subversion/trunk/subversion/tests/cmdline/input_validation_tests.py?rev=1160204&r1=1160203&r2=1160204&view=diff
==============================================================================
--- subversion/trunk/subversion/tests/cmdline/input_validation_tests.py
(original)
+++ subversion/trunk/subversion/tests/cmdline/input_validation_tests.py Mon Aug
22 11:11:50 2011
@@ -120,9 +120,6 @@ def invalid_diff_targets(sbox):
for (target1, target2) in [("iota", "^/"), ("file://", "iota")]:
run_and_verify_svn_in_wc(sbox, "svn: E205000: Cannot mix repository and
working "
"copy targets", 'diff', target1, target2)
- run_and_verify_svn_in_wc(sbox, "svn: E200007: Summarizing diff can only
compare "
- "repository to repository",
- 'diff', '--summarize', "iota", "A")
def invalid_export_targets(sbox):
"invalid targets for 'export'"