Philip Martin <philip.mar...@wandisco.com> writes:

> It's also hard to fix 1.8, how do we pass the information into the
> client library without changing the API?  Perhaps we could recognise a
> special part of the command name or a special external parameter, so
>
>    --diff-cmd svn:interactive:myscript

Another user raised the issue

http://subversion.tigris.org/issues/show_bug.cgi?id=4382

Using '--diff-cmd colordiff' to get coloured output no longer works.

Here's a solution that requires the user to mark the command as
requiring direct access.  Log and patch:

Allow the user to bypass the temporary spool file when invoking an
external diff command.  This allows commands that expect to see
a terminal to work.  The user adds the prefix 'svn:direct:' to the
command and Subversion passes the stream's file rather than creating
a spool file.  So

   --diff-cmd foo

runs foo with a spool file and

   --diff-cmd svn:direct:foo

runs foo with the stream's file.


* subversion/include/private/svn_io_private.h
  (svn_stream__aprfile, svn_io__file_for_command_stream): New.

* subversion/libsvn_subr/io.c
  (svn_io__file_for_command_stream): New.

* subversion/libsvn_subr/stream.c
  (struct svn_stream_t): Add file member.
  (svn_stream_create, svn_stream_from_aprfile2): Set file member.
  (svn_stream__aprfile): New.

* subversion/libsvn_client/diff.c
  (diff_content_changed): Use svn_io__file_for_command_stream.

* subversion/svnlook/svnlook.c
  (print_diff_tree): Use svn_io__file_for_command_stream.

Index: subversion/include/private/svn_io_private.h
===================================================================
--- subversion/include/private/svn_io_private.h (revision 1495378)
+++ subversion/include/private/svn_io_private.h (working copy)
@@ -90,7 +90,29 @@ svn_stream__set_is_buffered(svn_stream_t *stream,
 svn_boolean_t
 svn_stream__is_buffered(svn_stream_t *stream);
 
+/** Return the underlying file, if any, associated with the stream, or
+ * NULL if not available.  Accessing the file bypasses the stream and
+ * should only be done when such bypass is acceptable.
+ */
+apr_file_t *
+svn_stream__aprfile(svn_stream_t *stream);
 
+/** Examine ORIG_COMMAND to determine whether it requests direct
+ * access to the file, if so then return STREAM's file in *FILE and set
+ * *FILENAME to NULL or return an error if the file is not available.
+ * Otherwise return a temporary file in *FILE and the filename in
+ * *FILENAME.  Return the true command in * *TRUE_COMMAND.
+ */
+svn_error_t *
+svn_io__file_for_command_stream(apr_file_t **file,
+                                const char **filename,
+                                const char **true_command,
+                                svn_stream_t *stream,
+                                const char *orig_command,
+                                apr_pool_t *result_pool,
+                                apr_pool_t *scratch_pool);
+
+
 #ifdef __cplusplus
 }
 #endif /* __cplusplus */
Index: subversion/libsvn_client/diff.c
===================================================================
--- subversion/libsvn_client/diff.c     (revision 1495378)
+++ subversion/libsvn_client/diff.c     (working copy)
@@ -51,6 +51,7 @@
 #include "private/svn_wc_private.h"
 #include "private/svn_diff_private.h"
 #include "private/svn_subr_private.h"
+#include "private/svn_io_private.h"
 
 #include "svn_private_config.h"
 
@@ -793,6 +794,7 @@ diff_content_changed(svn_boolean_t *wrote_header,
       const char *outfilename;
       const char *errfilename;
       svn_stream_t *stream;
+      const char *diff_cmd;
 
       /* Print out the diff header. */
       SVN_ERR(svn_stream_printf_from_utf8(outstream,
@@ -807,11 +809,13 @@ diff_content_changed(svn_boolean_t *wrote_header,
        * ### a non-git compatible diff application.*/
 
       /* We deal in streams, but svn_io_run_diff2() deals in file handles,
-         unfortunately, so we need to make these temporary files, and then
+         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,
-                                       scratch_pool, scratch_pool));
+      SVN_ERR(svn_io__file_for_command_stream(&outfile, &outfilename,
+                                              &diff_cmd, outstream,
+                                              diff_cmd_baton->diff_cmd,
+                                              scratch_pool, scratch_pool));
+
       SVN_ERR(svn_io_open_unique_file3(&errfile, &errfilename, NULL,
                                        svn_io_file_del_on_pool_cleanup,
                                        scratch_pool, scratch_pool));
@@ -822,17 +826,21 @@ diff_content_changed(svn_boolean_t *wrote_header,
                                label1, label2,
                                tmpfile1, tmpfile2,
                                &exitcode, outfile, errfile,
-                               diff_cmd_baton->diff_cmd, scratch_pool));
+                               diff_cmd, scratch_pool));
 
-      SVN_ERR(svn_io_file_close(outfile, scratch_pool));
+      if (outfilename)
+        SVN_ERR(svn_io_file_close(outfile, scratch_pool));
       SVN_ERR(svn_io_file_close(errfile, scratch_pool));
 
       /* Now, open and copy our files to our output streams. */
-      SVN_ERR(svn_stream_open_readonly(&stream, outfilename,
-                                       scratch_pool, scratch_pool));
-      SVN_ERR(svn_stream_copy3(stream, svn_stream_disown(outstream,
-                               scratch_pool),
-                               NULL, NULL, scratch_pool));
+      if (outfilename)
+        {
+          SVN_ERR(svn_stream_open_readonly(&stream, outfilename,
+                                           scratch_pool, scratch_pool));
+          SVN_ERR(svn_stream_copy3(stream, svn_stream_disown(outstream,
+                                                             scratch_pool),
+                                   NULL, NULL, scratch_pool));
+        }
       SVN_ERR(svn_stream_open_readonly(&stream, errfilename,
                                        scratch_pool, scratch_pool));
       SVN_ERR(svn_stream_copy3(stream, svn_stream_disown(errstream,
Index: subversion/libsvn_subr/io.c
===================================================================
--- subversion/libsvn_subr/io.c (revision 1495378)
+++ subversion/libsvn_subr/io.c (working copy)
@@ -2854,7 +2854,44 @@ svn_io_run_cmd(const char *path,
   return svn_io_wait_for_cmd(&cmd_proc, cmd, exitcode, exitwhy, pool);
 }
 
+svn_error_t *
+svn_io__file_for_command_stream(apr_file_t **file,
+                                const char **filename,
+                                const char **true_command,
+                                svn_stream_t *stream,
+                                const char *orig_command,
+                                apr_pool_t *result_pool,
+                                apr_pool_t *scratch_pool)
+{
+  const char direct_magic[] = "svn:direct:";
+  svn_boolean_t direct_required = !strncmp(direct_magic, orig_command,
+                                           sizeof(direct_magic) - 1);
+  
+  if (direct_required)
+    {
+      /* The user doesn't want a temporary file, probably because
+         they want some sort of terminal.  We assume they don't
+         care that any output from the command may not be ordered
+         with the stream output. */
+      *file = svn_stream__aprfile(stream);
+      if (!*file)
+        return svn_error_createf(SVN_ERR_UNSUPPORTED_FEATURE, NULL,
+                                 "stream does not support direct use");
+      *filename = NULL;
+      *true_command = apr_pstrdup(result_pool,
+                                  orig_command + sizeof(direct_magic) - 1);
+    }
+  else
+    {
+      SVN_ERR(svn_io_open_unique_file3(file, filename, NULL,
+                                       svn_io_file_del_on_pool_cleanup,
+                                       scratch_pool, scratch_pool));
+      *true_command = apr_pstrdup(result_pool, orig_command);
+    }
 
+  return SVN_NO_ERROR;
+}
+
 svn_error_t *
 svn_io_run_diff2(const char *dir,
                  const char *const *user_args,
Index: subversion/libsvn_subr/stream.c
===================================================================
--- subversion/libsvn_subr/stream.c     (revision 1495378)
+++ subversion/libsvn_subr/stream.c     (working copy)
@@ -56,6 +56,7 @@ struct svn_stream_t {
   svn_stream_mark_fn_t mark_fn;
   svn_stream_seek_fn_t seek_fn;
   svn_stream__is_buffered_fn_t is_buffered_fn;
+  apr_file_t *file; /* Maybe NULL */
 };
 
 
@@ -81,6 +82,7 @@ svn_stream_create(void *baton, apr_pool_t *pool)
   stream->mark_fn = NULL;
   stream->seek_fn = NULL;
   stream->is_buffered_fn = NULL;
+  stream->file = NULL;
   return stream;
 }
 
@@ -913,6 +915,7 @@ svn_stream_from_aprfile2(apr_file_t *file,
   svn_stream_set_mark(stream, mark_handler_apr);
   svn_stream_set_seek(stream, seek_handler_apr);
   svn_stream__set_is_buffered(stream, is_buffered_handler_apr);
+  stream->file = file;
 
   if (! disown)
     svn_stream_set_close(stream, close_handler_apr);
@@ -920,6 +923,12 @@ svn_stream_from_aprfile2(apr_file_t *file,
   return stream;
 }
 
+apr_file_t *
+svn_stream__aprfile(svn_stream_t *stream)
+{
+  return stream->file;
+}
+
 
 /* Compressed stream support */
 
Index: subversion/svnlook/svnlook.c
===================================================================
--- subversion/svnlook/svnlook.c        (revision 1495378)
+++ subversion/svnlook/svnlook.c        (working copy)
@@ -57,6 +57,7 @@
 #include "private/svn_diff_private.h"
 #include "private/svn_cmdline_private.h"
 #include "private/svn_fspath.h"
+#include "private/svn_io_private.h"
 
 #include "svn_private_config.h"
 
@@ -957,6 +958,7 @@ print_diff_tree(svn_stream_t *out_stream,
               int exitcode;
               const char *orig_label;
               const char *new_label;
+              const char *diff_cmd;
 
               diff_cmd_argv = NULL;
               diff_cmd_argc = c->diff_options->nelts;
@@ -983,10 +985,11 @@ print_diff_tree(svn_stream_t *out_stream,
               SVN_ERR(generate_label(&new_label, root, path, pool));
 
               /* We deal in streams, but svn_io_run_diff2() deals in file
-                 handles, unfortunately, so we need to make these temporary
+                 handles, 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__file_for_command_stream(&outfile, &outfilename,
+                                                      &diff_cmd, out_stream,
+                                                      c->diff_cmd, pool, 
pool));
               SVN_ERR(svn_io_open_unique_file3(&errfile, &errfilename, NULL,
                         svn_io_file_del_on_pool_cleanup, pool, pool));
 
@@ -996,18 +999,22 @@ print_diff_tree(svn_stream_t *out_stream,
                                        orig_label, new_label,
                                        orig_path, new_path,
                                        &exitcode, outfile, errfile,
-                                       c->diff_cmd, pool));
+                                       diff_cmd, pool));
 
-              SVN_ERR(svn_io_file_close(outfile, pool));
+              if (outfilename)
+                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. */
+              if (outfilename)
+                {
+                  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_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,

-- 
Philip Martin | Subversion Committer
WANdisco | Non-Stop Data
www.wandisco.com

Reply via email to