Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

System.Process: stderr の内容が見たい #448

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
7 changes: 7 additions & 0 deletions autoload/vital/__vital__/System/Process.vim
Expand Up @@ -58,6 +58,7 @@ function! s:execute(args, ...) abort
\ 'background': 0,
\ 'encode_input': 1,
\ 'encode_output': 1,
\ 'encode_error': 1,
\ 'split_output': 1,
\ 'debug': &verbose,
\}, get(a:000, 0, {}))
Expand All @@ -74,6 +75,12 @@ function! s:execute(args, ...) abort
\ : &encoding
let result.output = s:String.iconv(result.output, 'char', encoding)
endif
if s:Prelude.is_string(result.error) && !empty(options.encode_error)
let encoding = s:Prelude.is_string(options.encode_error)
\ ? options.encode_error
\ : &encoding
let result.error = s:String.iconv(result.error, 'char', encoding)
endif
if options.split_output
let result.content = s:String.split_posix_text(result.output)
endif
Expand Down
1 change: 1 addition & 0 deletions autoload/vital/__vital__/System/Process/Mock.vim
Expand Up @@ -19,6 +19,7 @@ function! s:execute(args, options) abort
return {
\ 'status': 0,
\ 'output': 'Output of System.Process.Mock',
\ 'error': '',
\}
endfunction

Expand Down
3 changes: 3 additions & 0 deletions autoload/vital/__vital__/System/Process/System.vim
Expand Up @@ -54,6 +54,7 @@ function! s:execute(args, options) abort
\ (exists('+shellslash') ? '&shellslash' : ''),
\], '!empty(v:val)')
\)
let stderr = tempname()
try
" Reset shell related options
if s:Prelude.is_windows()
Expand Down Expand Up @@ -81,6 +82,7 @@ function! s:execute(args, options) abort
if a:options.background && !s:Prelude.is_windows()
let cmdline = cmdline . ' &'
endif
let cmdline .= printf(' 2>%s', fnameescape(stderr))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fnameescape() はコマンドラインモードで使うやつっす。使うなら shellescape() かと。

if a:options.debug > 0
echomsg printf(
\ 'vital: System.Process.System: %s',
Expand Down Expand Up @@ -108,6 +110,7 @@ function! s:execute(args, options) abort
return {
\ 'status': status,
\ 'output': output,
\ 'error': s:String.join_posix_lines(readfile(stderr)),
\ 'cmdline': cmdline,
\}
finally
Expand Down
5 changes: 5 additions & 0 deletions autoload/vital/__vital__/System/Process/Vimproc.vim
Expand Up @@ -3,11 +3,13 @@ set cpoptions&vim

function! s:_vital_loaded(V) abort
let s:Prelude = a:V.import('Prelude')
let s:String = a:V.import('Data.String')
endfunction

function! s:_vital_depends() abort
return [
\ 'Prelude',
\ 'Data.String',
\]
endfunction

Expand Down Expand Up @@ -35,10 +37,12 @@ function! s:is_supported(options) abort
endfunction

function! s:execute(args, options) abort
let stderr = tempname()
let cmdline = join(map(
\ copy(a:args),
\ 'vimproc#shellescape(v:val)',
\))
let cmdline .= printf(' 2>%s', fnameescape(stderr))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

vimproc の場合はそもそも vimproc#system() は使わずに vimproc#pgroup_open() 的なのを使った方が正確に取れそうです。

if a:options.debug > 0
echomsg printf(
\ 'vital: System.Process.Vimproc: %s',
Expand All @@ -64,6 +68,7 @@ function! s:execute(args, options) abort
return {
\ 'status': status,
\ 'output': output,
\ 'error': s:String.join_posix_lines(readfile(stderr)),
\ 'errormsg': vimproc#get_last_errmsg(),
\ 'cmdline': cmdline,
\}
Expand Down
11 changes: 11 additions & 0 deletions doc/vital-system-process.txt
Expand Up @@ -99,6 +99,13 @@ execute({args}[, {options}])
value of 'encode_output'.
Default: 1

"encode_error"
A |String| or |Number|. If 1 is specified, "error" value in
{result} will be encoded by |iconv()| from "char" to |&encoding|.
If |String| is specified, it will be encoded from "char" to a
value of 'encode_error'.
Default: 1

"split_output"
If 1, a POSIX |List| of "output" value in {result} will be
embed into {result} dictionary as "content".
Expand Down Expand Up @@ -127,6 +134,10 @@ execute({args}[, {options}])
An output |String| of the process. It is encoded if
'encode_output' is specified in {options}.

"error"
An stderr |String| of the process. It is encoded if
'encode_error' is specified in {options}.

"content"
An output of the process as a |List| when "options.split_output"
is specified. Otherwise the attribute is missing.
Expand Down
41 changes: 40 additions & 1 deletion test/System/Process.vimspec
Expand Up @@ -45,7 +45,7 @@ Describe System.Process
Assert Equals(result.output, 'Output of System.Process.Mock')
End

It does not encode {options.input}/{result.output} if {options.encode_input}/{option.encode_output} are not specified
It does not encode {options.input}/{result.output}/{result.error} if {options.encode_input}/{option.encode_output}.{options.encode_error} are not specified
function! sv.String.iconv(...) abort
let self._iconv_args = a:000
endfunction
Expand All @@ -55,6 +55,7 @@ Describe System.Process
\ 'input': 'foobar',
\ 'encode_input': 0,
\ 'encode_output': 0,
\ 'encode_error': 0,
\})
Assert KeyNotExists(sv.String, '_iconv_args')
End
Expand All @@ -69,6 +70,7 @@ Describe System.Process
\ 'input': 'foobar',
\ 'encode_input': 1,
\ 'encode_output': 0,
\ 'encode_error': 0,
\})
Assert Equals(sv.String._iconv_args, ['foobar', &encoding, 'char'])
End
Expand All @@ -83,6 +85,7 @@ Describe System.Process
\ 'input': 'foobar',
\ 'encode_input': 'some_encoding',
\ 'encode_output': 0,
\ 'encode_error': 0,
\})
Assert Equals(sv.String._iconv_args, ['foobar', 'some_encoding', 'char'])
End
Expand All @@ -97,6 +100,7 @@ Describe System.Process
\ 'input': 'foobar',
\ 'encode_input': 0,
\ 'encode_output': 1,
\ 'encode_error': 0,
\})
Assert Equals(sv.String._iconv_args,
\ ['Output of System.Process.Mock', 'char', &encoding]
Expand All @@ -113,10 +117,45 @@ Describe System.Process
\ 'input': 'foobar',
\ 'encode_input': 0,
\ 'encode_output': 'some_encoding',
\ 'encode_error': 0,
\})
Assert Equals(sv.String._iconv_args,
\ ['Output of System.Process.Mock', 'char', 'some_encoding']
\)
End

It encode {result.error} from 'char' to &encoding if {options.encode_error} is specified
function! sv.String.iconv(...) abort
let self._iconv_args = a:000
endfunction
let Mock = s:V.import('System.Process.Mock')
let result = Process.execute(['foo', 'bar'], {
\ 'clients': [Mock],
\ 'input': 'foobar',
\ 'encode_input': 0,
\ 'encode_output': 0,
\ 'encode_error': 1,
\})
Assert Equals(sv.String._iconv_args,
\ ['', 'char', &encoding]
\)
End

It encode {result.error} from 'char' to {options.encode_error} if {options.encode_error} is specified
function! sv.String.iconv(...) abort
let self._iconv_args = a:000
endfunction
let Mock = s:V.import('System.Process.Mock')
let result = Process.execute(['foo', 'bar'], {
\ 'clients': [Mock],
\ 'input': 'foobar',
\ 'encode_input': 0,
\ 'encode_output': 0,
\ 'encode_error': 'some_encoding',
\})
Assert Equals(sv.String._iconv_args,
\ ['', 'char', 'some_encoding']
\)
End
End
End
20 changes: 20 additions & 0 deletions test/System/Process/System.vimspec
Expand Up @@ -126,6 +126,16 @@ Describe System.Process.System
Assert Equals(result.content, ['t e s t'])
End
endif

It returns stderr content in {result.stderr}
let args = s:cmd + ['echo Hello >&2']
let result = Process.execute(args, options)
Assert Equals(result.success, 1)
Assert Equals(result.status, 0)
Assert Equals(result.output, '')
Assert Equals(result.error, "Hello\n")
Assert Equals(result.content, [''])
End
End
End
else
Expand Down Expand Up @@ -233,6 +243,16 @@ Describe System.Process.System
Assert Equals(result.output, "t e s t\n")
Assert Equals(result.content, ['t e s t'])
End

It returns stderr content in {result.stderr}
let args = ['bash', '-c', 'echo Hello >&2']
let result = Process.execute(args, options)
Assert Equals(result.success, 1)
Assert Equals(result.status, 0)
Assert Equals(result.output, '')
Assert Equals(result.error, "Hello\n")
Assert Equals(result.content, [''])
End
End
End
endif
Expand Down
20 changes: 20 additions & 0 deletions test/System/Process/Vimproc.vimspec
Expand Up @@ -151,6 +151,16 @@ Describe System.Process.Vimproc
Assert Equals(result.content, ['t e s t'])
End
endif

It returns stderr content in {result.stderr}
let args = s:cmd + ['echo Hello >&2']
let result = Process.execute(args, options)
Assert Equals(result.success, 1)
Assert Equals(result.status, 0)
Assert Equals(result.output, '')
Assert Equals(result.error, "Hello\n")
Assert Equals(result.content, [''])
End
End
End
else
Expand Down Expand Up @@ -272,6 +282,16 @@ Describe System.Process.Vimproc
Assert Equals(result.output, "t e s t\n")
Assert Equals(result.content, ['t e s t'])
End

It returns stderr content in {result.stderr}
let args = ['bash', '-c', 'echo Hello >&2']
let result = Process.execute(args, options)
Assert Equals(result.success, 1)
Assert Equals(result.status, 0)
Assert Equals(result.output, '')
Assert Equals(result.error, "Hello\n")
Assert Equals(result.content, [''])
End
End
End
endif
Expand Down