changeset 8447:6f26b680c243 v7.4.1514

commit https://github.com/vim/vim/commit/e98d12105213975f37b8d653bd909bd787a2cda9 Author: Bram Moolenaar <Bram@vim.org> Date: Tue Mar 8 15:37:41 2016 +0100 patch 7.4.1514 Problem: Channel output to file not implemented yet. Solution: Implement it for Unix.
author Christian Brabandt <cb@256bit.org>
date Tue, 08 Mar 2016 15:45:05 +0100
parents cef7be734b6e
children ee0e4e622697
files src/os_unix.c src/testdir/test_channel.vim src/testdir/test_channel_pipe.py src/version.c
diffstat 4 files changed, 145 insertions(+), 20 deletions(-) [+]
line wrap: on
line diff
--- a/src/os_unix.c
+++ b/src/os_unix.c
@@ -5046,13 +5046,18 @@ mch_start_job(char **argv, job_T *job, j
     int		fd_err[2];	/* for stderr */
     channel_T	*channel = NULL;
     int		use_file_for_in = options->jo_io[PART_IN] == JIO_FILE;
+    int		use_file_for_out = options->jo_io[PART_OUT] == JIO_FILE;
+    int		use_file_for_err = options->jo_io[PART_ERR] == JIO_FILE;
     int		use_out_for_err = options->jo_io[PART_ERR] == JIO_OUT;
 
     /* default is to fail */
     job->jv_status = JOB_FAILED;
     fd_in[0] = -1;
+    fd_in[1] = -1;
     fd_out[0] = -1;
+    fd_out[1] = -1;
     fd_err[0] = -1;
+    fd_err[1] = -1;
 
     /* TODO: without the channel feature connect the child to /dev/null? */
     /* Open pipes for stdin, stdout, stderr. */
@@ -5069,9 +5074,33 @@ mch_start_job(char **argv, job_T *job, j
     }
     else if (pipe(fd_in) < 0)
 	goto failed;
-    if (pipe(fd_out) < 0)
+
+    if (use_file_for_out)
+    {
+	char_u *fname = options->jo_io_name[PART_OUT];
+
+	fd_out[1] = mch_open((char *)fname, O_WRONLY | O_CREAT | O_TRUNC, 0644);
+	if (fd_out[1] < 0)
+	{
+	    EMSG2(_(e_notopen), fname);
+	    goto failed;
+	}
+    }
+    else if (pipe(fd_out) < 0)
 	goto failed;
-    if (!use_out_for_err && pipe(fd_err) < 0)
+
+    if (use_file_for_err)
+    {
+	char_u *fname = options->jo_io_name[PART_ERR];
+
+	fd_err[1] = mch_open((char *)fname, O_WRONLY | O_CREAT | O_TRUNC, 0600);
+	if (fd_err[1] < 0)
+	{
+	    EMSG2(_(e_notopen), fname);
+	    goto failed;
+	}
+    }
+    else if (!use_out_for_err && pipe(fd_err) < 0)
 	goto failed;
 
     channel = add_channel();
@@ -5117,14 +5146,16 @@ mch_start_job(char **argv, job_T *job, j
 	}
 	else
 	{
-	    close(fd_err[0]);
+	    if (!use_file_for_err)
+		close(fd_err[0]);
 	    close(2);
 	    ignored = dup(fd_err[1]);
 	    close(fd_err[1]);
 	}
 
 	/* set up stdout for the child */
-	close(fd_out[0]);
+	if (!use_file_for_out)
+	    close(fd_out[0]);
 	close(1);
 	ignored = dup(fd_out[1]);
 	close(fd_out[1]);
@@ -5148,13 +5179,15 @@ mch_start_job(char **argv, job_T *job, j
     /* child stdin, stdout and stderr */
     if (!use_file_for_in)
 	close(fd_in[0]);
-    close(fd_out[1]);
-    if (!use_out_for_err)
+    if (!use_file_for_out)
+	close(fd_out[1]);
+    if (!use_out_for_err && !use_file_for_err)
 	close(fd_err[1]);
     channel_set_pipes(channel,
 		      use_file_for_in ? INVALID_FD : fd_in[1],
-		      fd_out[0],
-		      use_out_for_err ? INVALID_FD : fd_err[0]);
+		      use_file_for_out ? INVALID_FD : fd_out[0],
+		      use_out_for_err || use_file_for_err
+						    ? INVALID_FD : fd_err[0]);
     channel_set_job(channel, job, options);
 #  ifdef FEAT_GUI
     channel_gui_register(channel);
@@ -5168,21 +5201,17 @@ failed: ;
     if (channel != NULL)
 	channel_free(channel);
     if (fd_in[0] >= 0)
-    {
 	close(fd_in[0]);
-	if (!use_file_for_in)
-	    close(fd_in[1]);
-    }
+    if (fd_in[1] >= 0)
+	close(fd_in[1]);
     if (fd_out[0] >= 0)
-    {
 	close(fd_out[0]);
+    if (fd_out[1] >= 0)
 	close(fd_out[1]);
-    }
     if (fd_err[0] >= 0)
-    {
 	close(fd_err[0]);
+    if (fd_err[1] >= 0)
 	close(fd_err[1]);
-    }
 # endif
 }
 
--- a/src/testdir/test_channel.vim
+++ b/src/testdir/test_channel.vim
@@ -555,6 +555,97 @@ func Test_nl_read_file()
   endtry
 endfunc
 
+func Test_nl_write_out_file()
+  if !has('job')
+    return
+  endif
+  " TODO: make this work for MS-Windows
+  if !has('unix')
+    return
+  endif
+  call ch_log('Test_nl_write_out_file()')
+  let job = job_start(s:python . " test_channel_pipe.py",
+	\ {'out-io': 'file', 'out-name': 'Xoutput'})
+  call assert_equal("run", job_status(job))
+  try
+    let handle = job_getchannel(job)
+    call ch_sendraw(handle, "echo line one\n")
+    call ch_sendraw(handle, "echo line two\n")
+    call ch_sendraw(handle, "double this\n")
+    for i in range(50)
+      sleep 10m
+      if len(readfile('Xoutput')) > 2
+	break
+      endif
+    endfor
+    call assert_equal(['line one', 'line two', 'this', 'AND this'], readfile('Xoutput'))
+  finally
+    call job_stop(job)
+    call delete('Xoutput')
+  endtry
+endfunc
+
+func Test_nl_write_err_file()
+  if !has('job')
+    return
+  endif
+  " TODO: make this work for MS-Windows
+  if !has('unix')
+    return
+  endif
+  call ch_log('Test_nl_write_err_file()')
+  let job = job_start(s:python . " test_channel_pipe.py",
+	\ {'err-io': 'file', 'err-name': 'Xoutput'})
+  call assert_equal("run", job_status(job))
+  try
+    let handle = job_getchannel(job)
+    call ch_sendraw(handle, "echoerr line one\n")
+    call ch_sendraw(handle, "echoerr line two\n")
+    call ch_sendraw(handle, "doubleerr this\n")
+    for i in range(50)
+      sleep 10m
+      if len(readfile('Xoutput')) > 2
+	break
+      endif
+    endfor
+    call assert_equal(['line one', 'line two', 'this', 'AND this'], readfile('Xoutput'))
+  finally
+    call job_stop(job)
+    call delete('Xoutput')
+  endtry
+endfunc
+
+func Test_nl_write_both_file()
+  if !has('job')
+    return
+  endif
+  " TODO: make this work for MS-Windows
+  if !has('unix')
+    return
+  endif
+  call ch_log('Test_nl_write_both_file()')
+  let job = job_start(s:python . " test_channel_pipe.py",
+	\ {'out-io': 'file', 'out-name': 'Xoutput', 'err-io': 'out'})
+  call assert_equal("run", job_status(job))
+  try
+    let handle = job_getchannel(job)
+    call ch_sendraw(handle, "echoerr line one\n")
+    call ch_sendraw(handle, "echo line two\n")
+    call ch_sendraw(handle, "double this\n")
+    call ch_sendraw(handle, "doubleerr that\n")
+    for i in range(50)
+      sleep 10m
+      if len(readfile('Xoutput')) > 5
+	break
+      endif
+    endfor
+    call assert_equal(['line one', 'line two', 'this', 'AND this', 'that', 'AND that'], readfile('Xoutput'))
+  finally
+    call job_stop(job)
+    call delete('Xoutput')
+  endtry
+endfunc
+
 func Test_pipe_to_buffer()
   if !has('job')
     return
--- a/src/testdir/test_channel_pipe.py
+++ b/src/testdir/test_channel_pipe.py
@@ -21,10 +21,13 @@ if __name__ == "__main__":
         if typed.startswith("echo "):
             print(typed[5:-1])
             sys.stdout.flush()
-        if typed.startswith("echoerr"):
+        if typed.startswith("double "):
+            print(typed[7:-1] + "\nAND " + typed[7:-1])
+            sys.stdout.flush()
+        if typed.startswith("echoerr "):
             print(typed[8:-1], file=sys.stderr)
             sys.stderr.flush()
-        if typed.startswith("double"):
-            print(typed[7:-1] + "\nAND " + typed[7:-1])
-            sys.stdout.flush()
+        if typed.startswith("doubleerr "):
+            print(typed[10:-1] + "\nAND " + typed[10:-1], file=sys.stderr)
+            sys.stderr.flush()
 
--- a/src/version.c
+++ b/src/version.c
@@ -744,6 +744,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    1514,
+/**/
     1513,
 /**/
     1512,