Hi,
I've made some changes to meet some feature requests regarding svn diff.
Could you please take a look and let me know if I'm on the right track?
thanks,
Gabriela
[[[
Change "svn diff" to allow removal of "-u" and use of arbitrary strings
in place of current hard-coded "-L" switch. This partially resolves.
http://subversion.tigris.org/issues/show_bug.cgi?id=2044
* subversion/svn/cl.h
(svn_cl__opt_state_t) Add two new fields.
* subversion/svn/svn.c
(svn_cl__longopt_t) Add new field.
(svn_cl__options) Add new field and help information.
(svn_cl__cmd_table) Add two new parameters.
(sub_main) Initialize new field.
(sub_main) Add new case.
(sub_main) Add conditional call to svn_config_set.
* subversion/svn/diff-cmd.c
(svn_cl__diff) Add braces and minor indentation issue?
(svn_cl__diff) Change call to svn_client_diff6 to svn_client_diff7.
* subversion/include/svn_config.h
() Add new declarations.
* subversion/include/svn_io.h
(svn_io_run_diff2_2) Add new function.
* subversion/include/svn_client.h
(svn_client_blame) Add new function. svn_client_diff7.
* subversion/libsvn_client/diff.c
(diff_cmd_baton) Add new field.
(diff_content_changed) Replace call to svn_io_run_diff2 with
svn_io_run_diff2_2.
(svn_client_diff7) Add new function.
* subversion/libsvn_subr/io.c
(svn_io_run_diff2_2) Add new function.
]]]
Index: subversion/libsvn_subr/io.c
===================================================================
--- subversion/libsvn_subr/io.c (revision 1458203)
+++ subversion/libsvn_subr/io.c (working copy)
@@ -2831,7 +2831,105 @@ svn_io_run_cmd(const char *path,
return svn_io_wait_for_cmd(&cmd_proc, cmd, exitcode, exitwhy, pool);
}
+svn_error_t *
+svn_io_run_diff2_2(const char *dir,
+ const char *const *user_args,
+ int num_user_args,
+ const char *label1,
+ const char *label2,
+ const char *user_label_string,
+ const char *from,
+ const char *to,
+ int *pexitcode,
+ apr_file_t *outfile,
+ apr_file_t *errfile,
+ const char *diff_cmd,
+ svn_boolean_t ext_string_present,
+ apr_pool_t *pool)
+{
+ const char **args;
+ int i;
+ int exitcode;
+ int nargs = 4; /* the diff command itself, two paths, plus a trailing NULL */
+ apr_pool_t *subpool = svn_pool_create(pool);
+ if (pexitcode == NULL)
+ pexitcode = &exitcode;
+
+ if (user_args != NULL)
+ nargs += num_user_args;
+ else
+ /* Handling the case where '-u ""' is provided, to avoid adding -u */
+ if (! ext_string_present)
+ nargs += 1; /* -u */
+
+ if (label1 != NULL)
+ nargs += 2; /* the -L and the label itself */
+ if (label2 != NULL)
+ nargs += 2; /* the -L and the label itself */
+
+ args = apr_palloc(subpool, nargs * sizeof(char *));
+
+ i = 0;
+ args[i++] = diff_cmd;
+
+ if (user_args != NULL)
+ {
+ int j;
+ for (j = 0; j < num_user_args; ++j)
+ args[i++] = user_args[j];
+ }
+ else
+ if (! ext_string_present)
+ args[i++] = "-u"; /* assume -u if the user didn't give us any args */
+
+ if (label1 != NULL)
+ {
+ if (! user_label_string)
+ args[i++] = "-L";
+ else
+ args[i++] = user_label_string;
+ args[i++] = label1;
+ }
+ if (label2 != NULL)
+ {
+ if (! user_label_string)
+ args[i++] = "-L";
+ else
+ args[i++] = user_label_string;
+ args[i++] = label2;
+ }
+
+ args[i++] = svn_dirent_local_style(from, subpool);
+ args[i++] = svn_dirent_local_style(to, subpool);
+ args[i++] = NULL;
+
+ SVN_ERR_ASSERT(i == nargs);
+
+ SVN_ERR(svn_io_run_cmd(dir, diff_cmd, args, pexitcode, NULL, TRUE,
+ NULL, outfile, errfile, subpool));
+
+ /* The man page for (GNU) diff describes the return value as:
+
+ "An exit status of 0 means no differences were found, 1 means
+ some differences were found, and 2 means trouble."
+
+ A return value of 2 typically occurs when diff cannot read its input
+ or write to its output, but in any case we probably ought to return an
+ error for anything other than 0 or 1 as the output is likely to be
+ corrupt.
+ */
+ if (*pexitcode != 0 && *pexitcode != 1)
+ return svn_error_createf(SVN_ERR_EXTERNAL_PROGRAM, NULL,
+ _("'%s' returned %d"),
+ svn_dirent_local_style(diff_cmd, pool),
+ *pexitcode);
+
+ svn_pool_destroy(subpool);
+
+ return SVN_NO_ERROR;
+}
+
svn_error_t *
svn_io_run_diff2(const char *dir,
const char *const *user_args,
Index: subversion/svn/svn.c
===================================================================
--- subversion/svn/svn.c (revision 1458203)
+++ subversion/svn/svn.c (working copy)
@@ -74,6 +74,7 @@ typedef enum svn_cl__longopt_t {
opt_config_options,
/* diff options */
opt_diff_cmd,
+ opt_diff_label,
opt_internal_diff,
opt_no_diff_added,
opt_no_diff_deleted,
@@ -336,6 +337,7 @@ const apr_getopt_option_t svn_cl__options[] =
{"diff", opt_diff, 0, N_("produce diff output")}, /* maps to show_diff */
/* diff options */
{"diff-cmd", opt_diff_cmd, 1, N_("use ARG as diff command")},
+ {"diff-label", opt_diff_label, 1, N_("use ARG as diff label switch")},
{"internal-diff", opt_internal_diff, 0,
N_("override diff-cmd specified in config file")},
{"no-diff-added", opt_no_diff_added, 0,
@@ -572,8 +574,8 @@ const svn_opt_subcommand_desc2_t svn_cl__cmd_table
" 5. Shorthand for 'svn diff --old=OLD-URL[@OLDREV] --new=NEW-PATH[@NEWREV]'\n"
" 6. Shorthand for 'svn diff --old=OLD-PATH[@OLDREV] --new=NEW-URL[@NEWREV]'\n"),
{'r', 'c', opt_old_cmd, opt_new_cmd, 'N', opt_depth, opt_diff_cmd,
- opt_internal_diff, 'x', opt_no_diff_added, opt_no_diff_deleted,
- opt_ignore_properties, opt_properties_only,
+ opt_internal_diff, opt_diff_label, 'x', opt_no_diff_added,
+ opt_no_diff_deleted, opt_ignore_properties, opt_properties_only,
opt_show_copies_as_adds, opt_notice_ancestry, opt_summarize, opt_changelist,
opt_force, opt_xml, opt_use_git_diff_format, opt_patch_compatible} },
{ "export", svn_cl__export, {0}, N_
@@ -2049,10 +2051,14 @@ sub_main(int argc, const char *argv[], apr_pool_t
case 'x':
SVN_INT_ERR(svn_utf_cstring_to_utf8(&opt_state.extensions,
opt_arg, pool));
+ opt_state.diff.ext_string_present = TRUE;
break;
case opt_diff_cmd:
opt_state.diff.diff_cmd = apr_pstrdup(pool, opt_arg);
break;
+ case opt_diff_label:
+ opt_state.diff.user_label_string = apr_pstrdup(pool, opt_arg);
+ break;
case opt_merge_cmd:
opt_state.merge_cmd = apr_pstrdup(pool, opt_arg);
break;
@@ -2656,6 +2662,10 @@ sub_main(int argc, const char *argv[], apr_pool_t
if (opt_state.diff.diff_cmd)
svn_config_set(cfg_config, SVN_CONFIG_SECTION_HELPERS,
SVN_CONFIG_OPTION_DIFF_CMD, opt_state.diff.diff_cmd);
+ if (opt_state.diff.user_label_string)
+ svn_config_set(cfg_config, SVN_CONFIG_SECTION_HELPERS,
+ SVN_CONFIG_OPTION_DIFF_USER_LABEL,
+ opt_state.diff.user_label_string);
if (opt_state.merge_cmd)
svn_config_set(cfg_config, SVN_CONFIG_SECTION_HELPERS,
SVN_CONFIG_OPTION_DIFF3_CMD, opt_state.merge_cmd);
Index: subversion/svn/cl.h
===================================================================
--- subversion/svn/cl.h (revision 1458203)
+++ subversion/svn/cl.h (working copy)
@@ -191,6 +191,9 @@ typedef struct svn_cl__opt_state_t
svn_boolean_t ignore_properties; /* ignore properties */
svn_boolean_t properties_only; /* Show properties only */
svn_boolean_t patch_compatible; /* Output compatible with GNU patch */
+ const char *user_label_string; /* Replacement for "-L" */
+ svn_boolean_t ext_string_present; /* T if '-x ... or --extensions ...'.
+ Used to detect if '-x ""' occurs */
} diff;
svn_boolean_t ignore_ancestry; /* ignore ancestry for merge-y operations */
svn_boolean_t ignore_externals;/* ignore externals definitions */
Index: subversion/svn/diff-cmd.c
===================================================================
--- subversion/svn/diff-cmd.c (revision 1458203)
+++ subversion/svn/diff-cmd.c (working copy)
@@ -387,7 +387,7 @@ svn_cl__diff(apr_getopt_t *os,
ctx, iterpool));
}
else
- SVN_ERR(svn_client_diff6(
+ SVN_ERR(svn_client_diff7(
options,
target1,
&(opt_state->start_revision),
@@ -401,6 +401,8 @@ svn_cl__diff(apr_getopt_t *os,
show_copies_as_adds,
opt_state->force,
ignore_properties,
+ opt_state->diff.user_label_string,
+ opt_state->diff.ext_string_present,
opt_state->diff.properties_only,
opt_state->diff.use_git_diff_format,
svn_cmdline_output_encoding(pool),
Index: subversion/include/svn_config.h
===================================================================
--- subversion/include/svn_config.h (revision 1458203)
+++ subversion/include/svn_config.h (working copy)
@@ -108,6 +108,7 @@ typedef struct svn_config_t svn_config_t;
#define SVN_CONFIG_OPTION_DIFF_EXTENSIONS "diff-extensions"
#define SVN_CONFIG_OPTION_DIFF3_CMD "diff3-cmd"
#define SVN_CONFIG_OPTION_DIFF3_HAS_PROGRAM_ARG "diff3-has-program-arg"
+#define SVN_CONFIG_OPTION_DIFF_USER_LABEL "diff-user-label"
#define SVN_CONFIG_OPTION_MERGE_TOOL_CMD "merge-tool-cmd"
#define SVN_CONFIG_SECTION_MISCELLANY "miscellany"
#define SVN_CONFIG_OPTION_GLOBAL_IGNORES "global-ignores"
Index: subversion/include/svn_io.h
===================================================================
--- subversion/include/svn_io.h (revision 1458203)
+++ subversion/include/svn_io.h (working copy)
@@ -1779,6 +1779,43 @@ svn_io_run_cmd(const char *path,
* @since New in 1.6.0.
*/
svn_error_t *
+svn_io_run_diff2_2(const char *dir,
+ const char *const *user_args,
+ int num_user_args,
+ const char *label1,
+ const char *label2,
+ const char *user_label_string,
+ const char *from,
+ const char *to,
+ int *exitcode,
+ apr_file_t *outfile,
+ apr_file_t *errfile,
+ const char *diff_cmd,
+ svn_boolean_t ext_string_present,
+ apr_pool_t *pool);
+
+/** Invoke the configured @c diff program, with @a user_args (an array
+ * of utf8-encoded @a num_user_args arguments) if they are specified
+ * (that is, if @a user_args is non-NULL), or "-u" if they are not.
+ * If @a user_args is NULL, the value of @a num_user_args is ignored.
+ *
+ * Diff runs in utf8-encoded @a dir, and its exit status is stored in
+ * @a exitcode, if it is not @c NULL.
+ *
+ * If @a label1 and/or @a label2 are not NULL they will be passed to the diff
+ * process as the arguments of "-L" options. @a label1 and @a label2 are also
+ * in utf8, and will be converted to native charset along with the other args.
+ *
+ * @a from is the first file passed to diff, and @a to is the second. The
+ * stdout of diff will be sent to @a outfile, and the stderr to @a errfile.
+ *
+ * @a diff_cmd must be non-NULL.
+ *
+ * Do all allocation in @a pool.
+ * @since New in 1.6.0.
+ */
+svn_error_t *
+
svn_io_run_diff2(const char *dir,
const char *const *user_args,
int num_user_args,
Index: subversion/include/svn_client.h
===================================================================
--- subversion/include/svn_client.h (revision 1458203)
+++ subversion/include/svn_client.h (working copy)
@@ -3008,6 +3008,31 @@ svn_client_blame(const char *path_or_url,
* @since New in 1.8.
*/
svn_error_t *
+svn_client_diff7(const apr_array_header_t *diff_options,
+ const char *path_or_url1,
+ const svn_opt_revision_t *revision1,
+ const char *path_or_url2,
+ const svn_opt_revision_t *revision2,
+ 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,
+ svn_boolean_t ignore_properties,
+ const char *user_label_string,
+ svn_boolean_t ext_string_present,
+ svn_boolean_t properties_only,
+ svn_boolean_t use_git_diff_format,
+ const char *header_encoding,
+ svn_stream_t *outstream,
+ svn_stream_t *errstream,
+ const apr_array_header_t *changelists,
+ svn_client_ctx_t *ctx,
+ apr_pool_t *pool);
+
+svn_error_t *
svn_client_diff6(const apr_array_header_t *diff_options,
const char *path_or_url1,
const svn_opt_revision_t *revision1,
Index: subversion/libsvn_client/diff.c
===================================================================
--- subversion/libsvn_client/diff.c (revision 1458203)
+++ subversion/libsvn_client/diff.c (working copy)
@@ -534,7 +534,9 @@ struct diff_cmd_baton {
/* If non-null, the external diff command to invoke. */
const char *diff_cmd;
-
+ /* String to interpolate between file labels for external command
+ invocation */
+ const char *user_label_string;
/* 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
@@ -586,6 +588,9 @@ struct diff_cmd_baton {
/* Whether to show only property changes. */
svn_boolean_t properties_only;
+ /* Whether "-x ..." or "--extensions ..." was supplied */
+ svn_boolean_t ext_string_present;
+
/* Whether we're producing a git-style diff. */
svn_boolean_t use_git_diff_format;
@@ -816,13 +821,28 @@ diff_content_changed(svn_boolean_t *wrote_header,
svn_io_file_del_on_pool_cleanup,
scratch_pool, scratch_pool));
- SVN_ERR(svn_io_run_diff2(".",
+ SVN_ERR(svn_io_run_diff2_2(".",
diff_cmd_baton->options.for_external.argv,
diff_cmd_baton->options.for_external.argc,
label1, label2,
+ diff_cmd_baton->user_label_string,
tmpfile1, tmpfile2,
&exitcode, outfile, errfile,
- diff_cmd_baton->diff_cmd, scratch_pool));
+ diff_cmd_baton->diff_cmd,
+ diff_cmd_baton->ext_string_present,
+ scratch_pool));
+/* Note: previous function left in to make change clearer. To be removed
+ in "official" patch
+*/
+/* SVN_ERR(svn_io_run_diff2(".",
+ diff_cmd_baton->options.for_external.argv,
+ diff_cmd_baton->options.for_external.argc,
+ label1, label2,
+ tmpfile1, tmpfile2,
+ &exitcode, outfile, errfile,
+ diff_cmd_baton->diff_cmd,
+ scratch_pool));
+*/
SVN_ERR(svn_io_file_close(outfile, scratch_pool));
SVN_ERR(svn_io_file_close(errfile, scratch_pool));
@@ -2538,6 +2558,77 @@ set_up_diff_cmd_and_options(struct diff_cmd_baton
* These cases require server communication.
*/
svn_error_t *
+svn_client_diff7(const apr_array_header_t *options,
+ const char *path_or_url1,
+ const svn_opt_revision_t *revision1,
+ const char *path_or_url2,
+ const svn_opt_revision_t *revision2,
+ 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,
+ svn_boolean_t ignore_properties,
+ const char *user_label_string,
+ svn_boolean_t ext_string_present,
+ svn_boolean_t properties_only,
+ svn_boolean_t use_git_diff_format,
+ const char *header_encoding,
+ svn_stream_t *outstream,
+ svn_stream_t *errstream,
+ const apr_array_header_t *changelists,
+ svn_client_ctx_t *ctx,
+ apr_pool_t *pool)
+{
+ struct diff_cmd_baton diff_cmd_baton = { 0 };
+ svn_opt_revision_t peg_revision;
+
+ if (ignore_properties && properties_only)
+ return svn_error_create(SVN_ERR_INCORRECT_PARAMS, NULL,
+ _("Cannot ignore properties and show only "
+ "properties at the same time"));
+
+ /* We will never do a pegged diff from here. */
+ peg_revision.kind = svn_opt_revision_unspecified;
+
+ /* setup callback and baton */
+ diff_cmd_baton.orig_path_1 = path_or_url1;
+ diff_cmd_baton.orig_path_2 = path_or_url2;
+
+ SVN_ERR(set_up_diff_cmd_and_options(&diff_cmd_baton, options,
+ ctx->config, pool));
+ diff_cmd_baton.pool = pool;
+ diff_cmd_baton.outstream = outstream;
+ diff_cmd_baton.errstream = errstream;
+ diff_cmd_baton.header_encoding = header_encoding;
+ diff_cmd_baton.revnum1 = SVN_INVALID_REVNUM;
+ diff_cmd_baton.revnum2 = SVN_INVALID_REVNUM;
+
+ diff_cmd_baton.user_label_string = user_label_string;
+ diff_cmd_baton.ext_string_present = ext_string_present;
+ 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.no_copyfrom_on_add = show_copies_as_adds;
+
+ diff_cmd_baton.wc_ctx = ctx->wc_ctx;
+ diff_cmd_baton.ra_session = NULL;
+ diff_cmd_baton.anchor = NULL;
+
+ return do_diff(&diff_callbacks, &diff_cmd_baton, ctx,
+ path_or_url1, path_or_url2, revision1, revision2,
+ &peg_revision,
+ depth, ignore_ancestry, show_copies_as_adds,
+ use_git_diff_format, changelists, pool);
+}
+
+svn_error_t *
svn_client_diff6(const apr_array_header_t *options,
const char *path_or_url1,
const svn_opt_revision_t *revision1,