mirror of
https://github.com/vlang/v.git
synced 2025-09-13 14:32:26 +03:00
os: implement os.fd_is_pending/1, os.Process.pipe_read/1, os.Process.is_pending/1 (#19787)
This commit is contained in:
parent
a92700e93b
commit
50c22b5a12
15 changed files with 288 additions and 136 deletions
|
@ -1,74 +0,0 @@
|
|||
module main
|
||||
|
||||
import os
|
||||
|
||||
// this is a example script to show you stdin can be used and keep a process open
|
||||
|
||||
fn exec(cmd string) (string, int) {
|
||||
mut cmd2 := cmd
|
||||
mut out := ''
|
||||
mut line := ''
|
||||
mut rc := 0
|
||||
mut p := os.new_process('/bin/bash')
|
||||
|
||||
// there are methods missing to know if stderr/stdout has data as such its better to redirect bot on same FD
|
||||
// not so nice trick to run bash in bash and redirect stderr, maybe someone has a better solution
|
||||
p.set_args(['-c', 'bash 2>&1'])
|
||||
p.set_redirect_stdio()
|
||||
p.run()
|
||||
|
||||
p.stdin_write('${cmd2} && echo **OK**')
|
||||
os.fd_close(p.stdio_fd[0]) // important: close stdin so cmd can end by itself
|
||||
|
||||
for p.is_alive() {
|
||||
line = p.stdout_read()
|
||||
println(line)
|
||||
// line_err = p.stderr_read() //IF WE CALL STDERR_READ will block
|
||||
// we need a mechanism which allows us to check if stderr/stdout has data or it should never block
|
||||
// is not a good way, need to use a string buffer, is slow like this
|
||||
out += line
|
||||
if line.ends_with('**OK**\n') {
|
||||
out = out[0..(out.len - 7)]
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// println("read from stdout, should not block")
|
||||
// is not really needed but good test to see behaviour
|
||||
out += p.stdout_read()
|
||||
println('read done')
|
||||
|
||||
println(p.stderr_read())
|
||||
p.close()
|
||||
p.wait()
|
||||
if p.code > 0 {
|
||||
rc = 1
|
||||
println('ERROR:')
|
||||
println(cmd2)
|
||||
print(out)
|
||||
}
|
||||
|
||||
return out, rc
|
||||
}
|
||||
|
||||
fn main() {
|
||||
mut out := ''
|
||||
mut rc := 0
|
||||
|
||||
// find files from /tmp excluding files unlistable by current user
|
||||
|
||||
out, rc = exec("find /tmp/ -user \$UID; echo '******'")
|
||||
println(out)
|
||||
assert out.ends_with('******\n')
|
||||
|
||||
out, rc = exec('echo to stdout')
|
||||
assert out.contains('to stdout')
|
||||
|
||||
out, rc = exec('echo to stderr 1>&2')
|
||||
assert out.contains('to stderr')
|
||||
|
||||
out, rc = exec('ls /sssss')
|
||||
assert rc > 0 // THIS STILL GIVES AN ERROR !
|
||||
|
||||
println('test ok stderr & stdout is indeed redirected')
|
||||
}
|
97
examples/process/write_and_read_from_a_bash_child_process.v
Normal file
97
examples/process/write_and_read_from_a_bash_child_process.v
Normal file
|
@ -0,0 +1,97 @@
|
|||
module main
|
||||
|
||||
// This example shows how to communicate with a child process (`bash` in this case), by sending
|
||||
// commands to its stdin pipe, and reading responses from its stdout and stderr pipes.
|
||||
// Note, you can use `if p.is_pending(.stdout) {` and `if p.is_pending(.stderr) {`, to check if
|
||||
// there is available data in the pipes, without having to block in your main loop, if the data
|
||||
// is missing or just not available yet.
|
||||
import os
|
||||
import time
|
||||
|
||||
const tmp_folder = os.join_path(os.temp_dir(), 'process_folder')
|
||||
|
||||
const max_txt_files = 20
|
||||
|
||||
fn exec(cmd string) (string, int, string) {
|
||||
mut out := []string{}
|
||||
mut er := []string{}
|
||||
mut rc := 0
|
||||
|
||||
mut p := os.new_process('/bin/bash')
|
||||
p.set_redirect_stdio()
|
||||
p.run()
|
||||
|
||||
p.stdin_write('echo "START " && sleep 0.1 && ${cmd};\n')
|
||||
p.stdin_write('ECODE=\$?;\n')
|
||||
p.stdin_write('sleep 0.1;\n')
|
||||
p.stdin_write('exit \$ECODE;\n')
|
||||
|
||||
// Note, that you can also ensure that `bash` will exit, when the command finishes,
|
||||
// by closing its stdin pipe. In the above example, that is not needed however, since
|
||||
// the last `exit` command, will make it quit as well.
|
||||
// os.fd_close(p.stdio_fd[0])
|
||||
|
||||
for p.is_alive() {
|
||||
if data := p.pipe_read(.stderr) {
|
||||
eprintln('p.pipe_read .stderr, len: ${data.len:4} | data: `${data#[0..10]}`...')
|
||||
er << data
|
||||
}
|
||||
if data := p.pipe_read(.stdout) {
|
||||
eprintln('p.pipe_read .stdout, len: ${data.len:4} | data: `${data#[0..10]}`...')
|
||||
out << data
|
||||
}
|
||||
// avoid a busy loop, by sleeping a bit between each iteration
|
||||
time.sleep(2 * time.millisecond)
|
||||
}
|
||||
|
||||
// the process finished, slurp all the remaining data in the pipes:
|
||||
out << p.stdout_slurp()
|
||||
er << p.stderr_slurp()
|
||||
p.close()
|
||||
p.wait()
|
||||
|
||||
if p.code > 0 {
|
||||
eprintln('----------------------------------------------------------')
|
||||
eprintln('COMMAND: ${cmd}')
|
||||
eprintln('STDOUT:\n${out}')
|
||||
eprintln('STDERR:\n${er}')
|
||||
eprintln('----------------------------------------------------------')
|
||||
rc = 1
|
||||
}
|
||||
|
||||
return out.join(''), rc, er.join('')
|
||||
}
|
||||
|
||||
fn main() {
|
||||
mut out := ''
|
||||
mut er := ''
|
||||
mut ecode := 0
|
||||
|
||||
// prepare some files in a temporary folder
|
||||
defer {
|
||||
os.rmdir_all(tmp_folder) or {}
|
||||
}
|
||||
os.mkdir_all(tmp_folder) or {}
|
||||
for i in 0 .. max_txt_files {
|
||||
os.write_file(os.join_path(tmp_folder, '${i}.txt'), '${i}\n${i}\n')!
|
||||
}
|
||||
|
||||
out, ecode, er = exec("find ${os.quoted_path(tmp_folder)} ; sleep 0.1; find ${os.quoted_path(tmp_folder)} ; echo '******'")
|
||||
assert out.ends_with('******\n')
|
||||
assert er == ''
|
||||
|
||||
out, ecode, er = exec('echo to stdout')
|
||||
assert out.contains('to stdout')
|
||||
assert er == ''
|
||||
|
||||
out, ecode, er = exec('echo to stderr 1>&2')
|
||||
assert out.starts_with('START')
|
||||
assert er.contains('to stderr')
|
||||
|
||||
out, ecode, er = exec('ls /sssss')
|
||||
assert out.starts_with('START')
|
||||
assert er != ''
|
||||
assert ecode > 0 // THIS STILL GIVES AN ERROR !
|
||||
|
||||
println('test ok stderr & stdout is indeed redirected, ecode: ${ecode}')
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue