diff options
Diffstat (limited to 'v_windows/v/cmd/tools/vbug.v')
-rw-r--r-- | v_windows/v/cmd/tools/vbug.v | 209 |
1 files changed, 209 insertions, 0 deletions
diff --git a/v_windows/v/cmd/tools/vbug.v b/v_windows/v/cmd/tools/vbug.v new file mode 100644 index 0000000..67fc186 --- /dev/null +++ b/v_windows/v/cmd/tools/vbug.v @@ -0,0 +1,209 @@ +import dl +import net.urllib +import os +import readline + +const vroot = @VMODROOT + +// get output from `v doctor` +fn get_vdoctor_output(is_verbose bool) string { + vexe := os.getenv('VEXE') + verbose_flag := if is_verbose { '-v' } else { '' } + result := os.execute('$vexe $verbose_flag doctor') + if result.exit_code != 0 { + eprintln('unable to get `v doctor` output: $result.output') + return '' + } + return result.output +} + +// get ouput from `v -g -o vdbg cmd/v && vdbg file.v` +fn get_v_build_output(is_verbose bool, is_yes bool, file_path string) string { + mut vexe := os.getenv('VEXE') + // prepare a V compiler with -g to have better backtraces if possible + wd := os.getwd() + os.chdir(vroot) or {} + verbose_flag := if is_verbose { '-v' } else { '' } + vdbg_path := $if windows { '$vroot/vdbg.exe' } $else { '$vroot/vdbg' } + vdbg_compilation_cmd := '"$vexe" $verbose_flag -g -o "$vdbg_path" cmd/v' + vdbg_result := os.execute(vdbg_compilation_cmd) + os.chdir(wd) or {} + if vdbg_result.exit_code == 0 { + vexe = vdbg_path + } else { + eprintln('unable to compile V in debug mode: $vdbg_result.output\ncommand: $vdbg_compilation_cmd\n') + } + // + mut result := os.execute('"$vexe" $verbose_flag "$file_path"') + defer { + os.rm(vdbg_path) or { + if is_verbose { + eprintln('unable to delete `vdbg`: $err') + } + } + } + if result.exit_code == 0 { + defer { + mut generated_file := file_path.all_before_last('.') + $if windows { + generated_file += '.exe' + } + os.rm(generated_file) or { + if is_verbose { + eprintln('unable to delete generated file: $err') + } + } + } + run := is_yes + || ask('It looks like the compilation went well, do you want to run the file?') + if run { + result = os.execute('"$vexe" $verbose_flag run "$file_path"') + if result.exit_code == 0 && !is_yes { + confirm_or_exit('It looks like the file ran correctly as well, are you sure you want to continue?') + } + } + } + return result.output +} + +type ShellExecuteWin = fn (voidptr, &u16, &u16, &u16, &u16, int) + +// open a uri using the default associated application +fn open_browser(uri string) ? { + $if macos { + result := os.execute('open "$uri"') + if result.exit_code != 0 { + return error('unable to open url: $result.output') + } + } $else $if freebsd || openbsd { + result := os.execute('xdg-open "$uri"') + if result.exit_code != 0 { + return error('unable to open url: $result.output') + } + } $else $if linux { + providers := ['xdg-open', 'x-www-browser', 'www-browser', 'wslview'] + + // There are multiple possible providers to open a browser on linux + // One of them is xdg-open, another is x-www-browser, then there's www-browser, etc. + // Look for one that exists and run it + for provider in providers { + if os.exists_in_system_path(provider) { + result := os.execute('$provider "$uri"') + if result.exit_code != 0 { + return error('unable to open url: $result.output') + } + break + } + } + } $else $if windows { + handle := dl.open_opt('shell32', dl.rtld_now) ? + // https://docs.microsoft.com/en-us/windows/win32/api/shellapi/nf-shellapi-shellexecutew + func := ShellExecuteWin(dl.sym_opt(handle, 'ShellExecuteW') ?) + func(C.NULL, 'open'.to_wide(), uri.to_wide(), C.NULL, C.NULL, C.SW_SHOWNORMAL) + dl.close(handle) + } $else { + return error('unsupported platform') + } +} + +fn ask(msg string) bool { + prompt := os.input_opt('$msg [Y/n] ') or { 'y' } + return prompt == '' || prompt[0].ascii_str().to_lower() != 'n' +} + +fn confirm_or_exit(msg string) { + if !ask(msg) { + exit(1) + } +} + +fn main() { + mut file_path := '' + mut is_verbose := false + mut is_yes := false + for arg in os.args[2..] { + match arg { + '-v' { + is_verbose = true + } + '-y' { + is_yes = true + } + else { + if !arg.ends_with('.v') && !arg.ends_with('.vsh') && !arg.ends_with('.vv') { + eprintln('unknown argument: `$arg`') + exit(1) + } + if file_path != '' { + eprintln('only one V file can be submitted') + exit(1) + } + file_path = arg + } + } + } + if file_path == '' { + eprintln('v bug: no v file listed to report') + exit(1) + } + // collect error information + // output from `v doctor` + vdoctor_output := get_vdoctor_output(is_verbose) + // file content + file_content := os.read_file(file_path) or { + eprintln('unable to get file "$file_path" content: $err') + '' + } + // output from `v -g -o vdbg cmd/v && vdbg file.v` + build_output := get_v_build_output(is_verbose, is_yes, file_path) + // ask the user if he wants to submit even after an error + if !is_yes && (vdoctor_output == '' || file_content == '' || build_output == '') { + confirm_or_exit('An error occured retrieving the information, do you want to continue?') + } + + expected_result := readline.read_line('What did you expect to see? ') or { + // Ctrl-C was pressed + eprintln('\nCanceled') + exit(1) + } + // open prefilled issue creation page, or print link as a fallback + + if !is_yes && vdoctor_output.contains('behind V master') { + confirm_or_exit('It looks like your installation of V is outdated, we advise you to run `v up` before submitting an issue. Are you sure you want to continue?') + } + + // When updating this template, make sure to update `.github/ISSUE_TEMPLATE/bug_report.md` too + raw_body := '<!-- It is advisable to update all relevant modules using `v outdated` and `v install` --> +**V doctor:** +``` +$vdoctor_output +``` + +**What did you do?** +`v -g -o vdbg cmd/v && vdbg $file_path` +{file_content} + +**What did you expect to see?** + +$expected_result + +**What did you see instead?** +``` +$build_output```' + mut encoded_body := urllib.query_escape(raw_body.replace_once('{file_content}', '```v\n$file_content\n```')) + mut generated_uri := 'https://github.com/vlang/v/issues/new?labels=Bug&body=$encoded_body' + if generated_uri.len > 8192 { + // GitHub doesn't support URLs longer than 8192 characters + encoded_body = urllib.query_escape(raw_body.replace_once('{file_content}', 'See attached file `$file_path`')) + generated_uri = 'https://github.com/vlang/v/issues/new?labels=Bug&body=$encoded_body' + println('Your file is too big to be submitted. Head over to the following URL and attach your file.') + println(generated_uri) + } else { + open_browser(generated_uri) or { + if is_verbose { + eprintln(err) + } + println(generated_uri) + } + } +} |