subversion-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From g..@apache.org
Subject svn commit: r1483945 - in /subversion/branches/invoke-diff-cmd-feature/subversion: include/ libsvn_client/ libsvn_subr/ svn/ tests/cmdline/
Date Fri, 17 May 2013 18:28:24 GMT
Author: gbg
Date: Fri May 17 18:28:23 2013
New Revision: 1483945

URL: http://svn.apache.org/r1483945
Log:
[[[
Add new diff option "--invoke-diff-cmd" which allows the user to
define a custom command line or config file entry for an external
diff program.

* subversion/include/svn_client.h 

  (svn_client_diff7, svn_client_diff_peg7): Declare the new API.  Like
    svn_client_diff[_peg]6 but with invoke_diff_cmd parameter.

  (svn_client_diff6, svn_client_diff_peg_6): Deprecate. 


* subversion/include/svn_config.h

  (SVN_CONFIG_OPTION_INVOKE_DIFF_CMD): New definition.


* subversion/include/svn_io.h

   (svn_io_create_custom_diff_cmd): New function.

   (svn_io_run_external_diff): New function.


* subversion/libsvn_client/deprecated.c

  (svn_client_diff6, svn_client_diff_peg6): New deprecation wrappers.


* subversion/libsvn_client/diff.c

  (struct diff_cmd_baton): New member: 'invoke_diff_cmd'.

  (diff_content_changed): Call svn_io_run_external_diff if
    --invoke-diff-cmd option was specified, otherwise retain previous
    behaviour.

  (set_up_diff_cmd_and_options): Apply invoke-diff-cmd option 
    preferentially.  Old behavior unchanged.
   
  (svn_client_diff_peg_7): Rename and update from
    svn_client_diff_peg_6.  Add new parameter: invoke_diff_cmd.

  (svn_client_diff7): Rename and update from svn_client_diff6, add
    new parameter 'invoke_diff_cmd'.  

  (): Update all comments mentioning 'svn_client_diff6' to
    'svn_client_diff7'.


* subversion/libsvn_subr/config_file.c

  (svn_config_ensure): New entry: invoke-diff-cmd. 


* subversion/libsvn_subr/io.c

  (svn_io_create_custom_diff_cmd): New function.

  (svn_io_run_external_diff): New function.


* subversion/svn/cl.h

  (struct svn_cl__opt_state_t.diff): New member: 'invoke_diff_cmd'.


* subversion/svn/diff-cmd.c

  (svn_cl__diff): Update call to svn_client_diff6 to svn_client_diff7.


* subversion/svn/svn.c

  (svn_cl__options[]): Add help info and new variable: 
    'opt_invoke_diff_cmd'.

  (svn_cl__cmd_table[]): New option: 'invoke-diff-cmd'.

  (sub_main): Prohibit simultaneous usage of --invoke-diff-cmd and
    --internal-diff. Add new opt_state.diff.invoke-diff-cmd option 
    to the option selector.  Add call to svn_config_set.


* subversion/tests/cmdline/diff_tests.py

  (diff_invoke_external_diffcmd): New function.

  (test_list): Add new entry 'diff_invoke_external_diffcmd'.


* tools/hook-scripts/argv_dump.pl

  (New File): Perl script that enumerates output by svn to assist with
    testing.

]]]

Modified:
    subversion/branches/invoke-diff-cmd-feature/subversion/include/svn_client.h
    subversion/branches/invoke-diff-cmd-feature/subversion/include/svn_config.h
    subversion/branches/invoke-diff-cmd-feature/subversion/include/svn_io.h
    subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_client/deprecated.c
    subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_client/diff.c
    subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_subr/config_file.c
    subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_subr/io.c
    subversion/branches/invoke-diff-cmd-feature/subversion/svn/cl.h
    subversion/branches/invoke-diff-cmd-feature/subversion/svn/diff-cmd.c
    subversion/branches/invoke-diff-cmd-feature/subversion/svn/svn.c
    subversion/branches/invoke-diff-cmd-feature/subversion/tests/cmdline/diff_tests.py

Modified: subversion/branches/invoke-diff-cmd-feature/subversion/include/svn_client.h
URL: http://svn.apache.org/viewvc/subversion/branches/invoke-diff-cmd-feature/subversion/include/svn_client.h?rev=1483945&r1=1483944&r2=1483945&view=diff
==============================================================================
--- subversion/branches/invoke-diff-cmd-feature/subversion/include/svn_client.h (original)
+++ subversion/branches/invoke-diff-cmd-feature/subversion/include/svn_client.h Fri May 17
18:28:23 2013
@@ -2986,6 +2986,11 @@ svn_client_blame(const char *path_or_url
  * The above two options are mutually exclusive. It is an error to set
  * both to TRUE.
  *
+ * @a invoke_diff_cmd is used to call an external diff program but may
+ * not be @c NULL.  The command line invocation will override the
+ * invoke-diff-cmd invocation entry(if any) in the Subversion
+ * configuration file.
+ *
  * Generated headers are encoded using @a header_encoding.
  *
  * Diff output will not be generated for binary files, unless @a
@@ -3016,8 +3021,38 @@ svn_client_blame(const char *path_or_url
  * @note @a relative_to_dir doesn't affect the path index generated by
  * external diff programs.
  *
+ * @since New in 1.9.
+ */
+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,
+                 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,
+                 const char *invoke_diff_cmd,
+                 svn_client_ctx_t *ctx,
+                 apr_pool_t *pool);
+
+/** Similar to svn_client_diff7(), but with @a invoke_diff_cmd.
+ *
+ * @deprecated Provided for backward compatibility with the 1.8 API.
  * @since New in 1.8.
  */
+SVN_DEPRECATED
 svn_error_t *
 svn_client_diff6(const apr_array_header_t *diff_options,
                  const char *path_or_url1,
@@ -3175,14 +3210,47 @@ svn_client_diff(const apr_array_header_t
  * be either a working-copy path or URL.
  *
  * If @a peg_revision is #svn_opt_revision_unspecified, behave
- * identically to svn_client_diff6(), using @a path_or_url for both of that
+ * identically to svn_client_diff7(), using @a path_or_url for both of that 
  * function's @a path_or_url1 and @a path_or_url2 arguments.
  *
- * All other options are handled identically to svn_client_diff6().
+ * All other options are handled identically to svn_client_diff7().
  *
- * @since New in 1.8.
+ * @since New in 1.9.
  */
 svn_error_t *
+svn_client_diff_peg7(const apr_array_header_t *diff_options,
+                     const char *path_or_url,
+                     const svn_opt_revision_t *peg_revision,
+                     const svn_opt_revision_t *start_revision,
+                     const svn_opt_revision_t *end_revision,
+                     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,
+                     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,
+                     const char *invoke_diff_cmd,
+                     svn_client_ctx_t *ctx,
+                     apr_pool_t *pool);
+         
+
+/** Similar to svn_client_peg5(), but with @a no_diff_added set to
+ *  FALSE, @a ignore_properties set to FALSE and @a properties_only
+ *  set to false.
+ *
+ * @deprecated Provided for backward compatibility with the 1.7 API.
+ * @since New in 1.9.
+ */
+SVN_DEPRECATED
+svn_error_t *
 svn_client_diff_peg6(const apr_array_header_t *diff_options,
                      const char *path_or_url,
                      const svn_opt_revision_t *peg_revision,

Modified: subversion/branches/invoke-diff-cmd-feature/subversion/include/svn_config.h
URL: http://svn.apache.org/viewvc/subversion/branches/invoke-diff-cmd-feature/subversion/include/svn_config.h?rev=1483945&r1=1483944&r2=1483945&view=diff
==============================================================================
--- subversion/branches/invoke-diff-cmd-feature/subversion/include/svn_config.h (original)
+++ subversion/branches/invoke-diff-cmd-feature/subversion/include/svn_config.h Fri May 17
18:28:23 2013
@@ -112,6 +112,8 @@ 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"
+/** @since New in 1.9. */
+#define SVN_CONFIG_OPTION_INVOKE_DIFF_CMD           "invoke-diff-cmd"
 #define SVN_CONFIG_OPTION_MERGE_TOOL_CMD            "merge-tool-cmd"
 #define SVN_CONFIG_SECTION_MISCELLANY           "miscellany"
 #define SVN_CONFIG_OPTION_GLOBAL_IGNORES            "global-ignores"

Modified: subversion/branches/invoke-diff-cmd-feature/subversion/include/svn_io.h
URL: http://svn.apache.org/viewvc/subversion/branches/invoke-diff-cmd-feature/subversion/include/svn_io.h?rev=1483945&r1=1483944&r2=1483945&view=diff
==============================================================================
--- subversion/branches/invoke-diff-cmd-feature/subversion/include/svn_io.h (original)
+++ subversion/branches/invoke-diff-cmd-feature/subversion/include/svn_io.h Fri May 17 18:28:23
2013
@@ -2278,6 +2278,38 @@ svn_io_file_readline(apr_file_t *file,
 
 /** @} */
 
+/** Parse a user defined command to contain dynamically created labels
+ *  and filenames.
+ *  
+ * @since New in 1.9.
+ */
+const char **
+svn_io_create_custom_diff_cmd(const char *label1,
+                              const char *label2,
+                              const char *label3,
+                              const char *tmpfile1,
+                              const char *tmpfile2,
+                              const char *base,
+                              const char *cmd,
+                              apr_pool_t *scratch_pool);
+
+/** Run the external diff command defined by the invoke-diff-cmd
+ *  option.
+ *  
+ *  @since New in 1.9.
+ */
+svn_error_t *
+svn_io_run_external_diff(const char *dir,
+                         const char *label1,
+                         const char *label2,
+                         const char *tmpfile1,
+                         const char *tmpfile2,
+                         int *pexitcode,
+                         apr_file_t *outfile,
+                         apr_file_t *errfile,
+                         const char *external_diff_cmd,
+                         apr_pool_t *scratch_pool);
+
 #ifdef __cplusplus
 }
 #endif /* __cplusplus */

Modified: subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_client/deprecated.c
URL: http://svn.apache.org/viewvc/subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_client/deprecated.c?rev=1483945&r1=1483944&r2=1483945&view=diff
==============================================================================
--- subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_client/deprecated.c (original)
+++ subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_client/deprecated.c Fri
May 17 18:28:23 2013
@@ -914,6 +914,53 @@ svn_client_delete(svn_client_commit_info
 /*** From diff.c ***/
 
 svn_error_t *
+svn_client_diff6(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,
+                 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)
+{
+  return svn_client_diff7(options,
+                          path_or_url1,
+                          revision1,
+                          path_or_url2,
+                          revision2,
+                          relative_to_dir,
+                          depth,
+                          ignore_ancestry,
+                          no_diff_added,
+                          no_diff_deleted,
+                          show_copies_as_adds,
+                          ignore_content_type,
+                          ignore_properties,
+                          properties_only,
+                          use_git_diff_format,
+                          header_encoding,
+                          outstream,
+                          errstream,
+                          changelists,
+                          NULL,
+                          ctx, 
+                          pool);
+}
+
+svn_error_t *
 svn_client_diff5(const apr_array_header_t *diff_options,
                  const char *path1,
                  const svn_opt_revision_t *revision1,
@@ -1036,6 +1083,53 @@ svn_client_diff(const apr_array_header_t
 }
 
 svn_error_t *
+svn_client_diff_peg6(const apr_array_header_t *options,
+                     const char *path_or_url,
+                     const svn_opt_revision_t *peg_revision,
+                     const svn_opt_revision_t *start_revision,
+                     const svn_opt_revision_t *end_revision,
+                     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,
+                     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)
+{
+  return svn_client_diff_peg7(options,
+                              path_or_url,
+                              peg_revision,
+                              start_revision,
+                              end_revision,
+                              relative_to_dir,
+                              depth,
+                              ignore_ancestry,
+                              no_diff_added,
+                              no_diff_deleted,
+                              show_copies_as_adds,
+                              ignore_content_type,
+                              ignore_properties,
+                              properties_only,
+                              use_git_diff_format,
+                              header_encoding,
+                              outstream,
+                              errstream,
+                              changelists,
+                              NULL,
+                              ctx,
+                              pool);
+}
+
+svn_error_t *
 svn_client_diff_peg5(const apr_array_header_t *diff_options,
                      const char *path,
                      const svn_opt_revision_t *peg_revision,

Modified: subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_client/diff.c
URL: http://svn.apache.org/viewvc/subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_client/diff.c?rev=1483945&r1=1483944&r2=1483945&view=diff
==============================================================================
--- subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_client/diff.c (original)
+++ subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_client/diff.c Fri May 17
18:28:23 2013
@@ -427,7 +427,7 @@ print_git_diff_header(svn_stream_t *os,
 
 /* A helper func that writes out verbal descriptions of property diffs
    to OUTSTREAM.   Of course, OUTSTREAM will probably be whatever was
-   passed to svn_client_diff6(), which is probably stdout.
+   passed to svn_client_diff7(), which is probably stdout.
 
    ### FIXME needs proper docstring
 
@@ -563,7 +563,7 @@ struct diff_cmd_baton {
   const char *orig_path_2;
 
   /* These are the numeric representations of the revisions passed to
-     svn_client_diff6(), either may be SVN_INVALID_REVNUM.  We need these
+     svn_client_diff7(), either may be SVN_INVALID_REVNUM.  We need these
      because some of the svn_wc_diff_callbacks4_t don't get revision
      arguments.
 
@@ -611,6 +611,10 @@ struct diff_cmd_baton {
 
   /* Whether the local diff target of a repos->wc diff is a copy. */
   svn_boolean_t repos_wc_diff_target_is_copy;
+
+  /* external custom diff command */
+  const char *invoke_diff_cmd;
+
 };
 
 /* An helper for diff_dir_props_changed, diff_file_changed and diff_file_added
@@ -786,7 +790,7 @@ diff_content_changed(svn_boolean_t *wrot
     }
 
 
-  if (diff_cmd_baton->diff_cmd)
+  if (diff_cmd_baton->diff_cmd || diff_cmd_baton->invoke_diff_cmd)
     {
       apr_file_t *outfile;
       apr_file_t *errfile;
@@ -815,15 +819,25 @@ diff_content_changed(svn_boolean_t *wrot
       SVN_ERR(svn_io_open_unique_file3(&errfile, &errfilename, NULL,
                                        svn_io_file_del_on_pool_cleanup,
                                        scratch_pool, scratch_pool));
-
-      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));
-
+      
+      if (diff_cmd_baton->diff_cmd) 
+        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));
+      else
+        { 
+          SVN_ERR(
+          svn_io_run_external_diff(".",
+                                   label1, label2,
+                                   tmpfile1, tmpfile2,
+                                   &exitcode, outfile, errfile,
+                                   diff_cmd_baton->invoke_diff_cmd,
+                                   scratch_pool));
+        }  
       SVN_ERR(svn_io_file_close(outfile, scratch_pool));
       SVN_ERR(svn_io_file_close(errfile, scratch_pool));
 
@@ -1519,8 +1533,8 @@ diff_prepare_repos_repos(const char **ur
 
 /* A Theoretical Note From Ben, regarding do_diff().
 
-   This function is really svn_client_diff6().  If you read the public
-   API description for svn_client_diff6(), it sounds quite Grand.  It
+   This function is really svn_client_diff7().  If you read the public
+   API description for svn_client_diff7(), it sounds quite Grand.  It
    sounds really generalized and abstract and beautiful: that it will
    diff any two paths, be they working-copy paths or URLs, at any two
    revisions.
@@ -1544,7 +1558,7 @@ diff_prepare_repos_repos(const char **ur
    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()
+   Perhaps someday a brave soul will truly make svn_client_diff7()
    perfectly general.  For now, we live with the 90% case.  Certainly,
    the commandline client only calls this function in legal ways.
    When there are other users of svn_client.h, maybe this will become
@@ -1557,7 +1571,7 @@ static svn_error_t *
 unsupported_diff_error(svn_error_t *child_err)
 {
   return svn_error_create(SVN_ERR_INCORRECT_PARAMS, child_err,
-                          _("Sorry, svn_client_diff6 was called in a way "
+                          _("Sorry, svn_client_diff7 was called in a way "
                             "that is not yet supported"));
 }
 
@@ -1566,7 +1580,7 @@ unsupported_diff_error(svn_error_t *chil
    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_diff6(). */
+   All other options are the same as those passed to svn_client_diff7(). */
 static svn_error_t *
 diff_wc_wc(const char *path1,
            const svn_opt_revision_t *revision1,
@@ -1649,7 +1663,7 @@ diff_wc_wc(const char *path1,
    and the actual two paths compared are determined by following copy
    history from PATH_OR_URL2.
 
-   All other options are the same as those passed to svn_client_diff6(). */
+   All other options are the same as those passed to svn_client_diff7(). */
 static svn_error_t *
 diff_repos_repos(const svn_wc_diff_callbacks4_t *callbacks,
                  struct diff_cmd_baton *callback_baton,
@@ -1794,7 +1808,7 @@ diff_repos_repos(const svn_wc_diff_callb
    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(). */
+   All other options are the same as those passed to svn_client_diff7(). */
 static svn_error_t *
 diff_repos_wc(const char *path_or_url1,
               const svn_opt_revision_t *revision1,
@@ -2129,7 +2143,7 @@ do_diff(const svn_wc_diff_callbacks4_t *
    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(). */
+   All other options are the same as those passed to svn_client_diff7(). */
 static svn_error_t *
 diff_summarize_repos_wc(svn_client_diff_summarize_func_t summarize_func,
                         void *summarize_baton,
@@ -2173,7 +2187,7 @@ diff_summarize_repos_wc(svn_client_diff_
    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_diff6(). */
+   All other options are the same as those passed to svn_client_diff7(). */
 static svn_error_t *
 diff_summarize_wc_wc(svn_client_diff_summarize_func_t summarize_func,
                      void *summarize_baton,
@@ -2448,30 +2462,43 @@ set_up_diff_cmd_and_options(struct diff_
 {
   const char *diff_cmd = NULL;
 
-  /* See if there is a diff command and/or diff arguments. */
+  /* old style diff_cmd has precedence in config file */
   if (config)
     {
       svn_config_t *cfg = svn_hash_gets(config, SVN_CONFIG_CATEGORY_CONFIG);
       svn_config_get(cfg, &diff_cmd, SVN_CONFIG_SECTION_HELPERS,
                      SVN_CONFIG_OPTION_DIFF_CMD, NULL);
       if (options == NULL)
-        {
-          const char *diff_extensions;
-          svn_config_get(cfg, &diff_extensions, SVN_CONFIG_SECTION_HELPERS,
-                         SVN_CONFIG_OPTION_DIFF_EXTENSIONS, NULL);
-          if (diff_extensions)
-            options = svn_cstring_split(diff_extensions, " \t\n\r", TRUE, pool);
-        }
+      {
+        const char *diff_extensions;
+        svn_config_get(cfg, &diff_extensions, SVN_CONFIG_SECTION_HELPERS,
+                       SVN_CONFIG_OPTION_DIFF_EXTENSIONS, NULL);
+        if (diff_extensions)
+          options = svn_cstring_split(diff_extensions, " \t\n\r", TRUE, pool);
+      }
     }
-
   if (options == NULL)
     options = apr_array_make(pool, 0, sizeof(const char *));
 
   if (diff_cmd)
     SVN_ERR(svn_path_cstring_to_utf8(&diff_cmd_baton->diff_cmd, diff_cmd,
                                      pool));
-  else
-    diff_cmd_baton->diff_cmd = NULL;
+  else {
+    if (config) /* check if there is a invoke_diff_cmd in the config file */
+     {
+       svn_config_t *cfg = svn_hash_gets(config, SVN_CONFIG_CATEGORY_CONFIG);
+       diff_cmd_baton->diff_cmd = NULL; 
+       svn_config_get(cfg, &diff_cmd, SVN_CONFIG_SECTION_HELPERS,
+                      SVN_CONFIG_OPTION_INVOKE_DIFF_CMD, NULL);
+       if (diff_cmd) 
+       {
+         SVN_ERR(svn_path_cstring_to_utf8(
+                   &diff_cmd_baton->invoke_diff_cmd, diff_cmd, pool));
+         
+      return SVN_NO_ERROR;
+       }
+     }
+   }
 
   /* If there was a command, arrange options to pass to it. */
   if (diff_cmd_baton->diff_cmd)
@@ -2537,7 +2564,7 @@ set_up_diff_cmd_and_options(struct diff_
       * These cases require server communication.
 */
 svn_error_t *
-svn_client_diff6(const apr_array_header_t *options,
+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,
@@ -2556,6 +2583,7 @@ svn_client_diff6(const apr_array_header_
                  svn_stream_t *outstream,
                  svn_stream_t *errstream,
                  const apr_array_header_t *changelists,
+                 const char *invoke_diff_cmd,
                  svn_client_ctx_t *ctx,
                  apr_pool_t *pool)
 {
@@ -2573,7 +2601,8 @@ svn_client_diff6(const apr_array_header_
   /* setup callback and baton */
   diff_cmd_baton.orig_path_1 = path_or_url1;
   diff_cmd_baton.orig_path_2 = path_or_url2;
-
+  diff_cmd_baton.invoke_diff_cmd = invoke_diff_cmd;
+  
   SVN_ERR(set_up_diff_cmd_and_options(&diff_cmd_baton, options,
                                       ctx->config, pool));
   diff_cmd_baton.pool = pool;
@@ -2604,7 +2633,7 @@ svn_client_diff6(const apr_array_header_
 }
 
 svn_error_t *
-svn_client_diff_peg6(const apr_array_header_t *options,
+svn_client_diff_peg7(const apr_array_header_t *options,
                      const char *path_or_url,
                      const svn_opt_revision_t *peg_revision,
                      const svn_opt_revision_t *start_revision,
@@ -2623,6 +2652,7 @@ svn_client_diff_peg6(const apr_array_hea
                      svn_stream_t *outstream,
                      svn_stream_t *errstream,
                      const apr_array_header_t *changelists,
+                     const char *invoke_diff_cmd,
                      svn_client_ctx_t *ctx,
                      apr_pool_t *pool)
 {
@@ -2636,6 +2666,7 @@ svn_client_diff_peg6(const apr_array_hea
   /* setup callback and baton */
   diff_cmd_baton.orig_path_1 = path_or_url;
   diff_cmd_baton.orig_path_2 = path_or_url;
+  diff_cmd_baton.invoke_diff_cmd = invoke_diff_cmd;
 
   SVN_ERR(set_up_diff_cmd_and_options(&diff_cmd_baton, options,
                                       ctx->config, pool));

Modified: subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_subr/config_file.c
URL: http://svn.apache.org/viewvc/subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_subr/config_file.c?rev=1483945&r1=1483944&r2=1483945&view=diff
==============================================================================
--- subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_subr/config_file.c (original)
+++ subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_subr/config_file.c Fri May
17 18:28:23 2013
@@ -1084,6 +1084,11 @@ svn_config_ensure(const char *config_dir
         "### Set diff3-has-program-arg to 'yes' if your 'diff3' program"     NL
         "###   accepts the '--diff-program' option."                         NL
         "# diff3-has-program-arg = [yes | no]"                               NL
+        "### Set invoke-diff-cmd to the absolute path of your 'diff'"        NL
+        "### program."                                                       NL
+        "###   This will override the compile-time default, which is to use" NL
+        "###   Subversion's internal diff implementation."                   NL
+        "# invoke-diff-cmd = \"diff -y --label %l1% %f1% --label %l2% %f2%\""NL
         "### Set merge-tool-cmd to the command used to invoke your external" NL
         "### merging tool of choice. Subversion will pass 5 arguments to"    NL
         "### the specified command: base theirs mine merged wcfile"          NL

Modified: subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_subr/io.c
URL: http://svn.apache.org/viewvc/subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_subr/io.c?rev=1483945&r1=1483944&r2=1483945&view=diff
==============================================================================
--- subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_subr/io.c (original)
+++ subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_subr/io.c Fri May 17 18:28:23
2013
@@ -2921,6 +2921,137 @@ svn_io_run_diff2(const char *dir,
   return SVN_NO_ERROR;
 }
 
+const char **
+svn_io_create_custom_diff_cmd(const char *label1,
+                              const char *label2,
+                              const char *label3,
+                              const char *tmpfile1,
+                              const char *tmpfile2,
+                              const char *base,
+                              const char *cmd,
+                              apr_pool_t *pool)
+{
+  apr_pool_t *subpool; 
+  apr_array_header_t *tmp;
+  const char ** ret;
+  int argv;
+
+  subpool = svn_pool_create(pool);
+  
+  tmp = svn_cstring_split(cmd," ",TRUE, subpool);
+
+  ret = apr_pcalloc(pool, 
+                    tmp->nelts * 
+                    tmp->elt_size*sizeof(char *));  
+
+  for (argv = 0;  argv < tmp->nelts ; argv++)
+   {
+     svn_stringbuf_t *com;
+     int i;
+
+     com = svn_stringbuf_create_empty(subpool);
+     svn_stringbuf_appendcstr(com, APR_ARRAY_IDX(tmp, argv, char *));
+
+     for (i = 0; i < 6 /* sizeof(token_list) */; i++) 
+       {        
+         static const char *token_list[] = 
+           {"%f1%","%f2%", "%f3%", "%l1%", "%l2%","%l3%" };
+         svn_stringbuf_t *token;
+         int len;
+         char *found;
+
+         token = svn_stringbuf_create_empty(subpool);
+         svn_stringbuf_appendcstr(token, token_list[i]);
+         len = 0;
+
+         while ( (found = strstr(com->data, token->data)) && 
+                  (strlen(found) > len) ) 
+           {
+             len = strlen(found); 
+
+             /* if we find a % in front of this, consume it */
+             if (com->data[com->len - strlen(found)-1] == '%')
+               svn_stringbuf_remove(com, strlen(found)-1, 1);
+             else if (i == 0) /* %f1 */
+               svn_stringbuf_replace(com, com->len - strlen(found), token->len,
+                                     tmpfile1, strlen(tmpfile1));
+             else if (i == 1) /* %f2 */
+               svn_stringbuf_replace(com, com->len - strlen(found), token->len, 
+                                     tmpfile2, strlen(tmpfile2));
+             else if (i == 2) /* %f3 */
+               svn_stringbuf_replace(com, com->len - strlen(found), token->len, 
+                                     base, strlen(base));
+             else if (i == 3) /* %l1 */
+               svn_stringbuf_replace(com, com->len - strlen(found), token->len, 
+                                     label1, strlen(label1));
+             else if (i == 4) /* %l2 */
+	       svn_stringbuf_replace(com, com->len - strlen(found), token->len, 
+                                    label2, strlen(label2));
+	     else if (i == 5) /* %l3 */
+	       svn_stringbuf_replace(com, com->len - strlen(found), token->len, 
+                                    label3, strlen(label3));
+	   }
+       }
+     ret[argv] = com->data;
+   }  
+  ret[argv] = NULL;
+
+  svn_pool_destroy(subpool);
+  return ret;
+}
+
+svn_error_t *
+svn_io_run_external_diff(const char *dir,
+                         const char *label1,
+                         const char *label2,
+                         const char *tmpfile1,
+                         const char *tmpfile2,
+                         int *pexitcode,
+                         apr_file_t *outfile,
+                         apr_file_t *errfile,
+                         const char *external_diff_cmd,
+                         apr_pool_t *pool)
+{
+  int exitcode;
+  const char ** cmd;
+
+  if (0 == strlen(external_diff_cmd)) 
+     return svn_error_createf(SVN_ERR_CL_INSUFFICIENT_ARGS, NULL,
+                        _("The --invoke-diff-cmd string was empty.\n"));
+
+  cmd = svn_io_create_custom_diff_cmd(label1, label2, NULL, 
+                                      tmpfile1, tmpfile2, NULL, 
+                                      external_diff_cmd, pool);
+  if (pexitcode == NULL)
+     pexitcode = &exitcode;
+  
+  SVN_ERR(svn_io_run_cmd(dir, cmd[0], cmd, pexitcode, NULL, TRUE,
+                         NULL, outfile, errfile, pool));
+  
+  if (*pexitcode != 0 && *pexitcode != 1)
+   {
+       int i, size;
+       char * failed_command;
+
+       for (i = 0, size = 0; cmd[i]; i++) 
+         size += strlen(cmd[i]) + 1;
+
+       failed_command = apr_pcalloc(pool, size * sizeof(char *));
+
+       for (i = 0; cmd[i]; i++) 
+        {
+         strcat(failed_command, cmd[i]);
+         strcat(failed_command, " ");
+        }
+       
+       return svn_error_createf(SVN_ERR_EXTERNAL_PROGRAM, NULL,
+                                _("'%s' was expanded to '%s' and returned %d\n"),
+                                external_diff_cmd,
+                                svn_dirent_local_style(failed_command, pool),
+                                *pexitcode);
+   }
+  return SVN_NO_ERROR;
+}
 
 svn_error_t *
 svn_io_run_diff3_3(int *exitcode,

Modified: subversion/branches/invoke-diff-cmd-feature/subversion/svn/cl.h
URL: http://svn.apache.org/viewvc/subversion/branches/invoke-diff-cmd-feature/subversion/svn/cl.h?rev=1483945&r1=1483944&r2=1483945&view=diff
==============================================================================
--- subversion/branches/invoke-diff-cmd-feature/subversion/svn/cl.h (original)
+++ subversion/branches/invoke-diff-cmd-feature/subversion/svn/cl.h Fri May 17 18:28:23 2013
@@ -184,6 +184,8 @@ typedef struct svn_cl__opt_state_t
     {
   const char *diff_cmd;              /* the external diff command to use
                                         (not converted to UTF-8) */
+  const char *invoke_diff_cmd;       /* the format string to specify args   */
+                                     /* for the external diff cmd           */
   svn_boolean_t internal_diff;       /* override diff_cmd in config file */
   svn_boolean_t no_diff_added;       /* do not show diffs for deleted files */
   svn_boolean_t no_diff_deleted;     /* do not show diffs for deleted files */

Modified: subversion/branches/invoke-diff-cmd-feature/subversion/svn/diff-cmd.c
URL: http://svn.apache.org/viewvc/subversion/branches/invoke-diff-cmd-feature/subversion/svn/diff-cmd.c?rev=1483945&r1=1483944&r2=1483945&view=diff
==============================================================================
--- subversion/branches/invoke-diff-cmd-feature/subversion/svn/diff-cmd.c (original)
+++ subversion/branches/invoke-diff-cmd-feature/subversion/svn/diff-cmd.c Fri May 17 18:28:23
2013
@@ -404,7 +404,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),
@@ -424,6 +424,7 @@ svn_cl__diff(apr_getopt_t *os,
                      outstream,
                      errstream,
                      opt_state->changelists,
+                     opt_state->diff.invoke_diff_cmd,                        
                      ctx, iterpool));
         }
       else
@@ -455,7 +456,7 @@ svn_cl__diff(apr_getopt_t *os,
                                 ctx, iterpool));
             }
           else
-            SVN_ERR(svn_client_diff_peg6(
+            SVN_ERR(svn_client_diff_peg7(
                      options,
                      truepath,
                      &peg_revision,
@@ -475,6 +476,7 @@ svn_cl__diff(apr_getopt_t *os,
                      outstream,
                      errstream,
                      opt_state->changelists,
+                     opt_state->diff.invoke_diff_cmd,
                      ctx, iterpool));
         }
     }

Modified: subversion/branches/invoke-diff-cmd-feature/subversion/svn/svn.c
URL: http://svn.apache.org/viewvc/subversion/branches/invoke-diff-cmd-feature/subversion/svn/svn.c?rev=1483945&r1=1483944&r2=1483945&view=diff
==============================================================================
--- subversion/branches/invoke-diff-cmd-feature/subversion/svn/svn.c (original)
+++ subversion/branches/invoke-diff-cmd-feature/subversion/svn/svn.c Fri May 17 18:28:23 2013
@@ -84,6 +84,7 @@ typedef enum svn_cl__longopt_t {
   opt_ignore_properties,
   opt_properties_only,
   opt_patch_compatible,
+  opt_invoke_diff_cmd,
   /* end of diff options */
   opt_dry_run,
   opt_editor_cmd,
@@ -336,6 +337,25 @@ const apr_getopt_option_t svn_cl__option
   {"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")},
+  {"invoke-diff-cmd",      opt_invoke_diff_cmd, 1, 
+                   N_("use ARG as format string for external diff command\n"
+                      "                             "
+                      "invocation. \n                                         \n" 
+                      "                             "
+                      "Substitutions: %f1% %f2%  files to compare             \n"
+                      "                             "
+                      "               %l1% %l2%  user defined labels          \n"
+                      "                             "
+                      "Examples: --invoke-diff-cmd=\"diff -y %f1% %f2%        \n"       
  
+                      "                             "
+                      "   --invoke-diff-cmd=\"kdiff3 -auto -o /home/u/log \\  \n"
+                      "                             "
+                      "     %f1% %f2% --L1 %l1% --L2 \"Custom Label\" \"      \n"
+                      "                             "
+                      "The switch symbol '%' can be escaped in the usual way  \n"       
  
+                      "                             "
+                      "using the '%' character: %%f1% will be passed as %f1%. \n"       
  
+     )},
   {"internal-diff", opt_internal_diff, 0,
                        N_("override diff-cmd specified in config file")},
   {"no-diff-added", opt_no_diff_added, 0,
@@ -575,7 +595,8 @@ const svn_opt_subcommand_desc2_t svn_cl_
      opt_internal_diff, '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} },
+     opt_force, opt_xml, opt_use_git_diff_format, opt_patch_compatible,
+     opt_invoke_diff_cmd} },
   { "export", svn_cl__export, {0}, N_
     ("Create an unversioned copy of a tree.\n"
      "usage: 1. export [-r REV] URL[@PEGREV] [PATH]\n"
@@ -2093,6 +2114,9 @@ sub_main(int argc, const char *argv[], a
       case opt_diff_cmd:
         opt_state.diff.diff_cmd = apr_pstrdup(pool, opt_arg);
         break;
+      case opt_invoke_diff_cmd:
+        opt_state.diff.invoke_diff_cmd = apr_pstrdup(pool, opt_arg);
+        break;
       case opt_merge_cmd:
         opt_state.merge_cmd = apr_pstrdup(pool, opt_arg);
         break;
@@ -2502,6 +2526,14 @@ sub_main(int argc, const char *argv[], a
       return EXIT_ERROR(err);
     }
 
+  if (opt_state.diff.invoke_diff_cmd && opt_state.diff.internal_diff)
+    {
+      err = svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+                             _("--invoke-diff-cmd and --internal-diff "
+                               "are mutually exclusive"));
+      return EXIT_ERROR(err);
+    }
+
   /* Ensure that 'revision_ranges' has at least one item, and make
      'start_revision' and 'end_revision' match that item. */
   if (opt_state.revision_ranges->nelts == 0)
@@ -2714,9 +2746,17 @@ sub_main(int argc, const char *argv[], a
 
   /* XXX: Only diff_cmd for now, overlay rest later and stop passing
      opt_state altogether? */
-  if (opt_state.diff.diff_cmd)
+  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);
+   }
+  else 
+    {
+      if (opt_state.diff.invoke_diff_cmd)
+        svn_config_set(cfg_config, SVN_CONFIG_SECTION_HELPERS,
+                       SVN_CONFIG_OPTION_INVOKE_DIFF_CMD, opt_state.diff.invoke_diff_cmd);
+    }
   if (opt_state.merge_cmd)
     svn_config_set(cfg_config, SVN_CONFIG_SECTION_HELPERS,
                    SVN_CONFIG_OPTION_DIFF3_CMD, opt_state.merge_cmd);

Modified: subversion/branches/invoke-diff-cmd-feature/subversion/tests/cmdline/diff_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/invoke-diff-cmd-feature/subversion/tests/cmdline/diff_tests.py?rev=1483945&r1=1483944&r2=1483945&view=diff
==============================================================================
--- subversion/branches/invoke-diff-cmd-feature/subversion/tests/cmdline/diff_tests.py (original)
+++ subversion/branches/invoke-diff-cmd-feature/subversion/tests/cmdline/diff_tests.py Fri
May 17 18:28:23 2013
@@ -3260,6 +3260,35 @@ def diff_external_diffcmd(sbox):
                                      'diff', '--diff-cmd', diff_script_path,
                                      iota_path)
 
+# Check the correct parsing of arguments for an external diff tool
+def diff_invoke_external_diffcmd(sbox):
+  "svn diff --diff-invoke-cmd passes correct args"
+
+  diff_script_path = os.path.abspath(".")+"/diff"
+
+  svntest.main.create_python_hook_script(diff_script_path, 'import sys\n'
+                                          'for arg in sys.argv[1:]:\n  print(arg)\n')
+  if sys.platform == 'win32':
+     diff_script_path = "%s.bat" % diff_script_path
+
+  sbox.build(read_only = True)
+  os.chdir(sbox.wc_dir)
+
+  iota_path = 'iota'
+  svntest.main.file_append(iota_path, "new text in iota")
+
+  expected_output = svntest.verify.ExpectedOutput([
+      "Index: iota\n",
+      "===================================================================\n",
+      "iota	(revision 1)\n",
+      os.path.abspath(svntest.wc.text_base_path("iota")) + "\n",
+      "iota	(working copy)\n",
+      os.path.abspath("iota") + "\n"])
+
+  svntest.actions.run_and_verify_svn(None, expected_output, [],
+   'diff',
+   '--invoke-diff-cmd='+diff_script_path+' %l1% %f1% %l2% %f2%',
+   iota_path)
 
 #----------------------------------------------------------------------
 # Diffing an unrelated repository URL against working copy with
@@ -4634,6 +4663,7 @@ test_list = [ None,
               diff_file_depth_empty,
               diff_wrong_extension_type,
               diff_external_diffcmd,
+              diff_invoke_external_diffcmd,
               diff_url_against_local_mods,
               diff_preexisting_rev_against_local_add,
               diff_git_format_wc_wc,



Mime
View raw message