You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by jc...@apache.org on 2012/11/26 01:17:44 UTC

svn commit: r1413449 - /subversion/trunk/subversion/svnlook/main.c

Author: jcorvel
Date: Mon Nov 26 00:17:43 2012
New Revision: 1413449

URL: http://svn.apache.org/viewvc?rev=1413449&view=rev
Log:
Add '--diff-cmd' option to 'svnlook diff'.

* subversion/svnlook/main.c
  (): New option '--diff-cmd' for 'svnlook diff'.
  (print_diff_tree): If '--diff-cmd' is set, use that to generate the diff.
   This code is entirely based on the handling of '--diff-cmd' in
   libsvn_client/diff.c.

Modified:
    subversion/trunk/subversion/svnlook/main.c

Modified: subversion/trunk/subversion/svnlook/main.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/svnlook/main.c?rev=1413449&r1=1413448&r2=1413449&view=diff
==============================================================================
--- subversion/trunk/subversion/svnlook/main.c (original)
+++ subversion/trunk/subversion/svnlook/main.c Mon Nov 26 00:17:43 2012
@@ -96,7 +96,8 @@ enum
     svnlook__copy_info,
     svnlook__xml_opt,
     svnlook__ignore_properties,
-    svnlook__properties_only
+    svnlook__properties_only,
+    svnlook__diff_cmd
   };
 
 /*
@@ -128,6 +129,9 @@ static const apr_getopt_option_t options
   {"no-diff-deleted",   svnlook__no_diff_deleted, 0,
    N_("do not print differences for deleted files")},
 
+  {"diff-cmd",          svnlook__diff_cmd, 1,
+   N_("use ARG as diff command")},
+
   {"ignore-properties",   svnlook__ignore_properties, 0,
    N_("ignore properties during the operation")},
 
@@ -227,8 +231,8 @@ static const svn_opt_subcommand_desc2_t 
    N_("usage: svnlook diff REPOS_PATH\n\n"
       "Print GNU-style diffs of changed files and properties.\n"),
    {'r', 't', svnlook__no_diff_deleted, svnlook__no_diff_added,
-    svnlook__diff_copy_from, 'x', svnlook__ignore_properties,
-    svnlook__properties_only} },
+    svnlook__diff_copy_from, svnlook__diff_cmd, 'x',
+    svnlook__ignore_properties, svnlook__properties_only} },
 
   {"dirs-changed", subcommand_dirschanged, {0},
    N_("usage: svnlook dirs-changed REPOS_PATH\n\n"
@@ -332,6 +336,7 @@ struct svnlook_opt_state
   svn_boolean_t quiet;            /* --quiet */
   svn_boolean_t ignore_properties;  /* --ignore_properties */
   svn_boolean_t properties_only;    /* --properties-only */
+  const char *diff_cmd;           /* --diff-cmd */
 };
 
 
@@ -353,6 +358,7 @@ typedef struct svnlook_ctxt_t
   const apr_array_header_t *diff_options;
   svn_boolean_t ignore_properties;
   svn_boolean_t properties_only;
+  const char *diff_cmd;
 
 } svnlook_ctxt_t;
 
@@ -967,18 +973,32 @@ print_diff_tree(svn_stream_t *out_stream
         }
       else
         {
-          svn_diff_t *diff;
-          svn_diff_file_options_t *opts = svn_diff_file_options_create(pool);
-
-          if (c->diff_options)
-            SVN_ERR(svn_diff_file_options_parse(opts, c->diff_options, pool));
-
-          SVN_ERR(svn_diff_file_diff_2(&diff, orig_path,
-                                       new_path, opts, pool));
-
-          if (svn_diff_contains_diffs(diff))
+          if (c->diff_cmd)
             {
-              const char *orig_label, *new_label;
+              apr_file_t *outfile;
+              apr_file_t *errfile;
+              const char *outfilename;
+              const char *errfilename;
+              svn_stream_t *stream;
+              svn_stream_t *err_stream;
+              const char **diff_cmd_argv;
+              int diff_cmd_argc;
+              int exitcode;
+              const char *orig_label;
+              const char *new_label;
+
+              diff_cmd_argv = NULL;
+              diff_cmd_argc = c->diff_options->nelts;
+              if (diff_cmd_argc)
+                {
+                  int i;
+                  diff_cmd_argv = apr_palloc(pool, 
+                                             diff_cmd_argc * sizeof(char *));
+                  for (i = 0; i < diff_cmd_argc; i++)
+                    SVN_ERR(svn_utf_cstring_to_utf8(&diff_cmd_argv[i],
+                              APR_ARRAY_IDX(c->diff_options, i, const char *),
+                              pool));
+                }
 
               /* Print diff header. */
               SVN_ERR(svn_stream_printf_from_utf8(out_stream, encoding, pool,
@@ -990,24 +1010,87 @@ print_diff_tree(svn_stream_t *out_stream
                 SVN_ERR(generate_label(&orig_label, base_root,
                                        base_path, pool));
               SVN_ERR(generate_label(&new_label, root, path, pool));
-              SVN_ERR(svn_diff_file_output_unified3
-                      (out_stream, diff, orig_path, new_path,
-                       orig_label, new_label,
-                       svn_cmdline_output_encoding(pool), NULL,
-                       opts->show_c_function, pool));
+
+              /* We deal in streams, but svn_io_run_diff2() deals in file
+                 handles, unfortunately, so we need to make these temporary
+                 files, and then copy the contents to our stream. */
+              SVN_ERR(svn_io_open_unique_file3(&outfile, &outfilename, NULL,
+                        svn_io_file_del_on_pool_cleanup, pool, pool));
+              SVN_ERR(svn_io_open_unique_file3(&errfile, &errfilename, NULL,
+                        svn_io_file_del_on_pool_cleanup, pool, pool));
+
+              SVN_ERR(svn_io_run_diff2(".",
+                                       diff_cmd_argv,
+                                       diff_cmd_argc,
+                                       orig_label, new_label,
+                                       orig_path, new_path,
+                                       &exitcode, outfile, errfile,
+                                       c->diff_cmd, pool));
+
+              SVN_ERR(svn_io_file_close(outfile, pool));
+              SVN_ERR(svn_io_file_close(errfile, pool));
+
+              /* Now, open and copy our files to our output streams. */
+              SVN_ERR(svn_stream_for_stderr(&err_stream, pool));
+              SVN_ERR(svn_stream_open_readonly(&stream, outfilename,
+                                               pool, pool));
+              SVN_ERR(svn_stream_copy3(stream,
+                                       svn_stream_disown(out_stream, pool),
+                                       NULL, NULL, pool));
+              SVN_ERR(svn_stream_open_readonly(&stream, errfilename,
+                                               pool, pool));
+              SVN_ERR(svn_stream_copy3(stream,
+                                       svn_stream_disown(err_stream, pool),
+                                       NULL, NULL, pool));
+
               SVN_ERR(svn_stream_printf_from_utf8(out_stream, encoding, pool,
                                                   "\n"));
               diff_header_printed = TRUE;
             }
-          else if (! node->prop_mod &&
-                  ((! c->no_diff_added && node->action == 'A') ||
-                   (! c->no_diff_deleted && node->action == 'D')))
+          else
             {
-              /* There was an empty file added or deleted in this revision.
-               * We can't print a diff, but we can at least print
-               * a diff header since we know what happened to this file. */
-              SVN_ERR(svn_stream_printf_from_utf8(out_stream, encoding, pool,
-                                                  "%s", header->data));
+              svn_diff_t *diff;
+              svn_diff_file_options_t *opts = svn_diff_file_options_create(pool);
+
+              if (c->diff_options)
+                SVN_ERR(svn_diff_file_options_parse(opts, c->diff_options, pool));
+
+              SVN_ERR(svn_diff_file_diff_2(&diff, orig_path,
+                                           new_path, opts, pool));
+
+              if (svn_diff_contains_diffs(diff))
+                {
+                  const char *orig_label, *new_label;
+
+                  /* Print diff header. */
+                  SVN_ERR(svn_stream_printf_from_utf8(out_stream, encoding, pool,
+                                                      "%s", header->data));
+
+                  if (orig_empty)
+                    SVN_ERR(generate_label(&orig_label, NULL, path, pool));
+                  else
+                    SVN_ERR(generate_label(&orig_label, base_root,
+                                           base_path, pool));
+                  SVN_ERR(generate_label(&new_label, root, path, pool));
+                  SVN_ERR(svn_diff_file_output_unified3
+                          (out_stream, diff, orig_path, new_path,
+                           orig_label, new_label,
+                           svn_cmdline_output_encoding(pool), NULL,
+                           opts->show_c_function, pool));
+                  SVN_ERR(svn_stream_printf_from_utf8(out_stream, encoding, pool,
+                                                      "\n"));
+                  diff_header_printed = TRUE;
+                }
+              else if (! node->prop_mod &&
+                      ((! c->no_diff_added && node->action == 'A') ||
+                       (! c->no_diff_deleted && node->action == 'D')))
+                {
+                  /* There was an empty file added or deleted in this revision.
+                   * We can't print a diff, but we can at least print
+                   * a diff header since we know what happened to this file. */
+                  SVN_ERR(svn_stream_printf_from_utf8(out_stream, encoding, pool,
+                                                      "%s", header->data));
+                }
             }
         }
     }
@@ -1845,6 +1928,7 @@ get_ctxt_baton(svnlook_ctxt_t **baton_p,
                                           " \t\n\r", TRUE, pool);
   baton->ignore_properties = opt_state->ignore_properties;
   baton->properties_only = opt_state->properties_only;
+  baton->diff_cmd = opt_state->diff_cmd;
 
   if (baton->txn_name)
     SVN_ERR(svn_fs_open_txn(&(baton->txn), baton->fs,
@@ -2354,6 +2438,10 @@ main(int argc, const char *argv[])
           opt_state.properties_only = TRUE;
           break;
 
+        case svnlook__diff_cmd:
+          opt_state.diff_cmd = opt_arg;
+          break;
+
         default:
           SVN_INT_ERR(subcommand_help(NULL, NULL, pool));
           svn_pool_destroy(pool);