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,

Reply via email to