summaryrefslogtreecommitdiff
path: root/subversion/svn/diff-cmd.c
diff options
context:
space:
mode:
Diffstat (limited to 'subversion/svn/diff-cmd.c')
-rw-r--r--subversion/svn/diff-cmd.c161
1 files changed, 99 insertions, 62 deletions
diff --git a/subversion/svn/diff-cmd.c b/subversion/svn/diff-cmd.c
index 3c62523..2cbd202 100644
--- a/subversion/svn/diff-cmd.c
+++ b/subversion/svn/diff-cmd.c
@@ -77,6 +77,12 @@ kind_to_word(svn_client_diff_summarize_kind_t kind)
}
}
+/* Baton for summarize_xml and summarize_regular */
+struct summarize_baton_t
+{
+ const char *anchor;
+};
+
/* Print summary information about a given change as XML, implements the
* svn_client_diff_summarize_func_t interface. The @a baton is a 'char *'
* representing the either the path to the working copy root or the url
@@ -86,10 +92,11 @@ summarize_xml(const svn_client_diff_summarize_t *summary,
void *baton,
apr_pool_t *pool)
{
+ struct summarize_baton_t *b = baton;
/* Full path to the object being diffed. This is created by taking the
* baton, and appending the target's relative path. */
- const char *path = *(const char **)baton;
- svn_stringbuf_t *sb = svn_stringbuf_create("", pool);
+ const char *path = b->anchor;
+ svn_stringbuf_t *sb = svn_stringbuf_create_empty(pool);
/* Tack on the target path, so we can differentiate between different parts
* of the output when we're given multiple targets. */
@@ -125,7 +132,8 @@ summarize_regular(const svn_client_diff_summarize_t *summary,
void *baton,
apr_pool_t *pool)
{
- const char *path = *(const char **)baton;
+ struct summarize_baton_t *b = baton;
+ const char *path = b->anchor;
/* Tack on the target path, so we can differentiate between different parts
* of the output when we're given multiple targets. */
@@ -166,12 +174,17 @@ svn_cl__diff(apr_getopt_t *os,
svn_client_ctx_t *ctx = ((svn_cl__cmd_baton_t *) baton)->ctx;
apr_array_header_t *options;
apr_array_header_t *targets;
- apr_file_t *outfile, *errfile;
- apr_status_t status;
+ svn_stream_t *outstream;
+ svn_stream_t *errstream;
const char *old_target, *new_target;
apr_pool_t *iterpool;
svn_boolean_t pegged_diff = FALSE;
+ svn_boolean_t show_copies_as_adds =
+ opt_state->diff.patch_compatible || opt_state->diff.show_copies_as_adds;
+ svn_boolean_t ignore_properties =
+ opt_state->diff.patch_compatible || opt_state->diff.ignore_properties;
int i;
+ struct summarize_baton_t summarize_baton;
const svn_client_diff_summarize_func_t summarize_func =
(opt_state->xml ? summarize_xml : summarize_regular);
@@ -180,26 +193,24 @@ svn_cl__diff(apr_getopt_t *os,
else
options = NULL;
- /* Get an apr_file_t representing stdout and stderr, which is where
+ /* Get streams representing stdout and stderr, which is where
we'll have the external 'diff' program print to. */
- if ((status = apr_file_open_stdout(&outfile, pool)))
- return svn_error_wrap_apr(status, _("Can't open stdout"));
- if ((status = apr_file_open_stderr(&errfile, pool)))
- return svn_error_wrap_apr(status, _("Can't open stderr"));
+ SVN_ERR(svn_stream_for_stdout(&outstream, pool));
+ SVN_ERR(svn_stream_for_stderr(&errstream, pool));
if (opt_state->xml)
{
svn_stringbuf_t *sb;
/* Check that the --summarize is passed as well. */
- if (!opt_state->summarize)
+ if (!opt_state->diff.summarize)
return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
_("'--xml' option only valid with "
"'--summarize' option"));
SVN_ERR(svn_cl__xml_print_header("diff", pool));
- sb = svn_stringbuf_create("", pool);
+ sb = svn_stringbuf_create_empty(pool);
svn_xml_make_open_tag(&sb, pool, svn_xml_normal, "paths", NULL);
SVN_ERR(svn_cl__error_checked_fputs(sb->data, stdout));
}
@@ -210,12 +221,13 @@ svn_cl__diff(apr_getopt_t *os,
if (! opt_state->old_target && ! opt_state->new_target
&& (targets->nelts == 2)
- && svn_path_is_url(APR_ARRAY_IDX(targets, 0, const char *))
- && svn_path_is_url(APR_ARRAY_IDX(targets, 1, const char *))
+ && (svn_path_is_url(APR_ARRAY_IDX(targets, 0, const char *))
+ || svn_path_is_url(APR_ARRAY_IDX(targets, 1, const char *)))
&& opt_state->start_revision.kind == svn_opt_revision_unspecified
&& opt_state->end_revision.kind == svn_opt_revision_unspecified)
{
- /* The 'svn diff OLD_URL[@OLDREV] NEW_URL[@NEWREV]' case matches. */
+ /* A 2-target diff where one or both targets are URLs. These are
+ * shorthands for some 'svn diff --old X --new Y' invocations. */
SVN_ERR(svn_opt_parse_path(&opt_state->start_revision, &old_target,
APR_ARRAY_IDX(targets, 0, const char *),
@@ -225,10 +237,16 @@ svn_cl__diff(apr_getopt_t *os,
pool));
targets->nelts = 0;
+ /* Set default start/end revisions based on target types, in the same
+ * manner as done for the corresponding '--old X --new Y' cases,
+ * (note that we have an explicit --new target) */
if (opt_state->start_revision.kind == svn_opt_revision_unspecified)
- opt_state->start_revision.kind = svn_opt_revision_head;
+ opt_state->start_revision.kind = svn_path_is_url(old_target)
+ ? svn_opt_revision_head : svn_opt_revision_working;
+
if (opt_state->end_revision.kind == svn_opt_revision_unspecified)
- opt_state->end_revision.kind = svn_opt_revision_head;
+ opt_state->end_revision.kind = svn_path_is_url(new_target)
+ ? svn_opt_revision_head : svn_opt_revision_working;
}
else if (opt_state->old_target)
{
@@ -241,9 +259,8 @@ svn_cl__diff(apr_getopt_t *os,
tmp = apr_array_make(pool, 2, sizeof(const char *));
APR_ARRAY_PUSH(tmp, const char *) = (opt_state->old_target);
APR_ARRAY_PUSH(tmp, const char *) = (opt_state->new_target
- ? opt_state->new_target
- : APR_ARRAY_IDX(tmp, 0,
- const char *));
+ ? opt_state->new_target
+ : opt_state->old_target);
SVN_ERR(svn_cl__args_to_target_array_print_reserved(&tmp2, os, tmp,
ctx, FALSE, pool));
@@ -264,10 +281,14 @@ svn_cl__diff(apr_getopt_t *os,
if (new_rev.kind != svn_opt_revision_unspecified)
opt_state->end_revision = new_rev;
+ /* For URLs, default to HEAD. For WC paths, default to WORKING if
+ * new target is explicit; if new target is implicitly the same as
+ * old target, then default the old to BASE and new to WORKING. */
if (opt_state->start_revision.kind == svn_opt_revision_unspecified)
opt_state->start_revision.kind = svn_path_is_url(old_target)
- ? svn_opt_revision_head : svn_opt_revision_base;
-
+ ? svn_opt_revision_head
+ : (opt_state->new_target
+ ? svn_opt_revision_working : svn_opt_revision_base);
if (opt_state->end_revision.kind == svn_opt_revision_unspecified)
opt_state->end_revision.kind = svn_path_is_url(new_target)
? svn_opt_revision_head : svn_opt_revision_working;
@@ -292,7 +313,10 @@ svn_cl__diff(apr_getopt_t *os,
old_target = "";
new_target = "";
- SVN_ERR(svn_cl__assert_homogeneous_target_type(targets));
+ SVN_ERR_W(svn_cl__assert_homogeneous_target_type(targets),
+ _("'svn diff [-r N[:M]] [TARGET[@REV]...]' does not support mixed "
+ "target types. Try using the --old and --new options or one of "
+ "the shorthand invocations listed in 'svn help diff'."));
working_copy_present = ! svn_path_is_url(APR_ARRAY_IDX(targets, 0,
const char *));
@@ -347,34 +371,41 @@ svn_cl__diff(apr_getopt_t *os,
else
target2 = svn_dirent_join(new_target, path, iterpool);
- if (opt_state->summarize)
- SVN_ERR(svn_client_diff_summarize2
- (target1,
- &opt_state->start_revision,
- target2,
- &opt_state->end_revision,
- opt_state->depth,
- ! opt_state->notice_ancestry,
- opt_state->changelists,
- summarize_func, &target1,
- ctx, iterpool));
+ if (opt_state->diff.summarize)
+ {
+ summarize_baton.anchor = target1;
+
+ SVN_ERR(svn_client_diff_summarize2(
+ target1,
+ &opt_state->start_revision,
+ target2,
+ &opt_state->end_revision,
+ opt_state->depth,
+ ! opt_state->diff.notice_ancestry,
+ opt_state->changelists,
+ summarize_func, &summarize_baton,
+ ctx, iterpool));
+ }
else
- SVN_ERR(svn_client_diff5
- (options,
+ SVN_ERR(svn_client_diff6(
+ options,
target1,
&(opt_state->start_revision),
target2,
&(opt_state->end_revision),
NULL,
opt_state->depth,
- ! opt_state->notice_ancestry,
- opt_state->no_diff_deleted,
- opt_state->show_copies_as_adds,
+ ! opt_state->diff.notice_ancestry,
+ opt_state->diff.no_diff_added,
+ opt_state->diff.no_diff_deleted,
+ show_copies_as_adds,
opt_state->force,
- opt_state->use_git_diff_format,
+ ignore_properties,
+ opt_state->diff.properties_only,
+ opt_state->diff.use_git_diff_format,
svn_cmdline_output_encoding(pool),
- outfile,
- errfile,
+ outstream,
+ errstream,
opt_state->changelists,
ctx, iterpool));
}
@@ -392,34 +423,40 @@ svn_cl__diff(apr_getopt_t *os,
peg_revision.kind = svn_path_is_url(path)
? svn_opt_revision_head : svn_opt_revision_working;
- if (opt_state->summarize)
- SVN_ERR(svn_client_diff_summarize_peg2
- (truepath,
- &peg_revision,
- &opt_state->start_revision,
- &opt_state->end_revision,
- opt_state->depth,
- ! opt_state->notice_ancestry,
- opt_state->changelists,
- summarize_func, &truepath,
- ctx, iterpool));
+ if (opt_state->diff.summarize)
+ {
+ summarize_baton.anchor = truepath;
+ SVN_ERR(svn_client_diff_summarize_peg2(
+ truepath,
+ &peg_revision,
+ &opt_state->start_revision,
+ &opt_state->end_revision,
+ opt_state->depth,
+ ! opt_state->diff.notice_ancestry,
+ opt_state->changelists,
+ summarize_func, &summarize_baton,
+ ctx, iterpool));
+ }
else
- SVN_ERR(svn_client_diff_peg5
- (options,
+ SVN_ERR(svn_client_diff_peg6(
+ options,
truepath,
&peg_revision,
&opt_state->start_revision,
&opt_state->end_revision,
NULL,
opt_state->depth,
- ! opt_state->notice_ancestry,
- opt_state->no_diff_deleted,
- opt_state->show_copies_as_adds,
+ ! opt_state->diff.notice_ancestry,
+ opt_state->diff.no_diff_added,
+ opt_state->diff.no_diff_deleted,
+ show_copies_as_adds,
opt_state->force,
- opt_state->use_git_diff_format,
+ ignore_properties,
+ opt_state->diff.properties_only,
+ opt_state->diff.use_git_diff_format,
svn_cmdline_output_encoding(pool),
- outfile,
- errfile,
+ outstream,
+ errstream,
opt_state->changelists,
ctx, iterpool));
}
@@ -427,7 +464,7 @@ svn_cl__diff(apr_getopt_t *os,
if (opt_state->xml)
{
- svn_stringbuf_t *sb = svn_stringbuf_create("", pool);
+ svn_stringbuf_t *sb = svn_stringbuf_create_empty(pool);
svn_xml_make_close_tag(&sb, pool, "paths");
SVN_ERR(svn_cl__error_checked_fputs(sb->data, stdout));
SVN_ERR(svn_cl__xml_print_footer("diff", pool));