mirror of
https://github.com/vlang/v.git
synced 2025-09-13 14:32:26 +03:00
tools: rewrite v timeout
, support killing the child process on timeout by default (#24367)
This commit is contained in:
parent
f8c35b43f6
commit
6d0eaa5328
1 changed files with 51 additions and 23 deletions
|
@ -1,43 +1,71 @@
|
||||||
import os
|
import os
|
||||||
import time
|
import time
|
||||||
import flag
|
import flag
|
||||||
|
import strconv
|
||||||
|
|
||||||
struct Context {
|
struct Context {
|
||||||
mut:
|
mut:
|
||||||
show_help bool
|
timeout f64
|
||||||
cmd_line_opts []string
|
cmd_args []string
|
||||||
full_cmd string
|
|
||||||
timeout f64
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
mut ctx := Context{}
|
mut fp := flag.new_flag_parser(os.args[1..])
|
||||||
args := arguments()
|
|
||||||
mut fp := flag.new_flag_parser(args#[1..])
|
|
||||||
fp.application('v timeout')
|
fp.application('v timeout')
|
||||||
fp.version('0.0.1')
|
fp.version('0.0.2')
|
||||||
fp.description('Run a command with a time limit. Example: `v timeout 0.3 v run examples/hello_world.v`')
|
fp.description('Run a command with a time limit. Example: `v timeout 0.3 v run examples/hello_world.v`')
|
||||||
fp.arguments_description('timeout_in_seconds CMD [ARGS]')
|
fp.arguments_description('timeout_in_seconds CMD [ARGS]')
|
||||||
fp.skip_executable()
|
fp.skip_executable()
|
||||||
fp.limit_free_args_to_at_least(2)!
|
fp.limit_free_args_to_at_least(2)!
|
||||||
ctx.show_help = fp.bool('help', `h`, false, 'Show this help screen.')
|
|
||||||
if ctx.show_help {
|
if fp.bool('help', `h`, false, 'Show this help screen.') {
|
||||||
println(fp.usage())
|
println(fp.usage())
|
||||||
exit(0)
|
exit(0)
|
||||||
}
|
}
|
||||||
ctx.cmd_line_opts = fp.finalize() or {
|
|
||||||
eprintln('> error: ${err}')
|
args := fp.finalize() or {
|
||||||
|
eprintln('Argument error: ${err}')
|
||||||
exit(125) // mimic the exit codes of `timeout` in coreutils
|
exit(125) // mimic the exit codes of `timeout` in coreutils
|
||||||
}
|
}
|
||||||
ctx.timeout = ctx.cmd_line_opts[0].f64()
|
|
||||||
ctx.cmd_line_opts = ctx.cmd_line_opts#[1..]
|
ctx := Context{
|
||||||
ctx.full_cmd = ctx.cmd_line_opts.join(' ')
|
timeout: strconv.atof64(args[0]) or {
|
||||||
spawn fn (ctx Context) {
|
eprintln('Invalid timeout: ${args[0]}')
|
||||||
tperiod := time.Duration(i64(ctx.timeout * time.second))
|
exit(125)
|
||||||
time.sleep(tperiod)
|
}
|
||||||
// eprintln('> error: timeout of ${tperiod.seconds():5.3f}s reached, before command finished; command was: `${ctx.full_cmd}`')
|
cmd_args: args[1..].clone()
|
||||||
exit(124)
|
}
|
||||||
}(ctx)
|
|
||||||
ecode := os.system(ctx.full_cmd)
|
mut p := os.new_process(ctx.cmd_args[0])
|
||||||
exit(ecode)
|
p.set_args(ctx.cmd_args[1..])
|
||||||
|
p.run()
|
||||||
|
if p.err != '' {
|
||||||
|
eprintln('Cannot execute: ${ctx.cmd_args.join(' ')}')
|
||||||
|
exit(if os.exists(ctx.cmd_args[0]) { 126 } else { 127 })
|
||||||
|
}
|
||||||
|
|
||||||
|
child_exit := chan int{}
|
||||||
|
|
||||||
|
spawn fn (mut p os.Process, ch chan int) {
|
||||||
|
p.wait()
|
||||||
|
ch <- p.code
|
||||||
|
ch.close()
|
||||||
|
}(mut p, child_exit)
|
||||||
|
|
||||||
|
mut exit_code := 0
|
||||||
|
select {
|
||||||
|
i64(ctx.timeout * time.second) {
|
||||||
|
p.signal_term()
|
||||||
|
time.sleep(2 * time.millisecond)
|
||||||
|
if p.is_alive() {
|
||||||
|
p.signal_kill()
|
||||||
|
}
|
||||||
|
p.wait()
|
||||||
|
exit_code = 124 // timeout
|
||||||
|
}
|
||||||
|
code := <-child_exit {
|
||||||
|
exit_code = code
|
||||||
|
}
|
||||||
|
}
|
||||||
|
exit(exit_code)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue