diff --git a/cmd/tools/vretry.v b/cmd/tools/vretry.v new file mode 100644 index 0000000000..6997842c92 --- /dev/null +++ b/cmd/tools/vretry.v @@ -0,0 +1,57 @@ +import os +import time +import flag + +struct Context { +mut: + show_help bool + timeout time.Duration + delay time.Duration + retries int +} + +fn main() { + mut context := Context{} + mut fp := flag.new_flag_parser(os.args#[1..]) + fp.application('v retry') + fp.version('0.0.1') + fp.description('Run the command CMD in a loop, untill it succeeds, or until a predetermined amount of seconds pass.') + fp.arguments_description('CMD') + fp.skip_executable() + fp.limit_free_args_to_at_least(1)! + context.show_help = fp.bool('help', `h`, false, 'Show this help screen.') + context.timeout = fp.float('timeout', `t`, 300.0, 'Timeout in seconds. Default: 300.0 seconds.') * time.second + context.delay = fp.float('delay', `d`, 1.0, 'Delay between each retry in seconds. Default: 1.0 second.') * time.second + context.retries = fp.int('retries', `r`, 999_999_999, 'Maximum number of retries. Default: 999_999_999.') + if context.show_help { + println(fp.usage()) + exit(0) + } + command_args := fp.finalize() or { + eprintln('Error: ${err}') + exit(1) + } + cmd := command_args.join(' ') + + spawn fn (context Context) { + time.sleep(context.timeout) + eprintln('error: exceeded maximum timeout (${context.timeout.seconds()}s)!') + exit(1) + }(context) + + mut res := 0 + mut i := 0 + for { + i++ + res = os.system(cmd) + if res == 0 { + break + } + if i >= context.retries { + eprintln('error: exceeded maximum number of retries (${context.retries})!') + exit(res) + } + time.sleep(context.delay) + } + exit(res) +} diff --git a/cmd/v/v.v b/cmd/v/v.v index f274c5bbed..ea8fb7e492 100644 --- a/cmd/v/v.v +++ b/cmd/v/v.v @@ -31,6 +31,7 @@ const external_tools = [ 'missdoc', 'repl', 'repeat', + 'retry', 'self', 'setup-freetype', 'shader',