2025-03-18 10:57:36 +02:00
import os
import time
import flag
2025-05-01 01:10:16 +08:00
import strconv
2025-03-18 10:57:36 +02:00
struct Context {
mut :
2025-05-01 01:10:16 +08:00
timeout f64
cmd_args [ ] string
2025-03-18 10:57:36 +02:00
}
fn main ( ) {
2025-05-01 01:10:16 +08:00
mut fp := flag . new_flag_parser ( os . args [ 1 .. ] )
2025-03-18 10:57:36 +02:00
fp . application ( ' v t i m e o u t ' )
2025-05-01 01:10:16 +08:00
fp . version ( ' 0 . 0 . 2 ' )
2025-03-18 10:57:36 +02:00
fp . description ( ' R u n a c o m m a n d w i t h a t i m e l i m i t . E x a m p l e : ` v t i m e o u t 0 . 3 v r u n e x a m p l e s / h e l l o _ w o r l d . v ` ' )
fp . arguments_description ( ' t i m e o u t _ i n _ s e c o n d s C M D [ A R G S ] ' )
fp . skip_executable ( )
fp . limit_free_args_to_at_least ( 2 ) !
2025-05-01 01:10:16 +08:00
if fp . bool ( ' h e l p ' , ` h ` , false , ' S h o w t h i s h e l p s c r e e n . ' ) {
2025-03-18 10:57:36 +02:00
println ( fp . usage ( ) )
exit ( 0 )
}
2025-05-01 01:10:16 +08:00
args := fp . finalize ( ) or {
eprintln ( ' A r g u m e n t e r r o r : $ { err } ' )
2025-03-18 10:57:36 +02:00
exit ( 125 ) // mimic the exit codes of `timeout` in coreutils
}
2025-05-01 01:10:16 +08:00
ctx := Context {
timeout : strconv . atof64 ( args [ 0 ] ) or {
eprintln ( ' I n v a l i d t i m e o u t : $ { args [ 0 ] } ' )
exit ( 125 )
}
cmd_args : args [ 1 .. ] . clone ( )
}
2025-05-01 08:37:14 +03:00
mut cmd := ctx . cmd_args [ 0 ]
if ! os . exists ( cmd ) {
cmd = os . find_abs_path_of_executable ( cmd ) or { cmd }
}
mut p := os . new_process ( cmd )
2025-05-01 01:10:16 +08:00
p . set_args ( ctx . cmd_args [ 1 .. ] )
p . run ( )
if p . err != ' ' {
eprintln ( ' C a n n o t e x e c u t e : $ { 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 )
2025-03-18 10:57:36 +02:00
}