v/cmd/tools/vbug.v

170 lines
4.9 KiB
V

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('${os.quoted_path(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 := '${os.quoted_path(vexe)} $verbose_flag -g -o ${os.quoted_path(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('${os.quoted_path(vexe)} $verbose_flag ${os.quoted_path(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('${os.quoted_path(vexe)} $verbose_flag run ${os.quoted_path(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
}
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)
}
os.unsetenv('VCOLORS')
// 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 {
os.open_uri(generated_uri) or {
if is_verbose {
eprintln(err)
}
println(generated_uri)
}
}
}