1 | import net.urllib |
2 | import os |
3 | import readline |
4 | |
5 | const vroot = @VMODROOT |
6 | |
7 | // get output from `v doctor` |
8 | fn get_vdoctor_output(is_verbose bool) string { |
9 | vexe := os.getenv('VEXE') |
10 | verbose_flag := if is_verbose { '-v' } else { '' } |
11 | result := os.execute('${os.quoted_path(vexe)} ${verbose_flag} doctor') |
12 | if result.exit_code != 0 { |
13 | eprintln('unable to get `v doctor` output: ${result.output}') |
14 | return '' |
15 | } |
16 | return result.output |
17 | } |
18 | |
19 | // get ouput from `v -g -o vdbg cmd/v && vdbg file.v` |
20 | fn get_v_build_output(is_verbose bool, is_yes bool, file_path string) string { |
21 | mut vexe := os.getenv('VEXE') |
22 | // prepare a V compiler with -g to have better backtraces if possible |
23 | wd := os.getwd() |
24 | os.chdir(vroot) or {} |
25 | verbose_flag := if is_verbose { '-v' } else { '' } |
26 | vdbg_path := $if windows { '${vroot}/vdbg.exe' } $else { '${vroot}/vdbg' } |
27 | vdbg_compilation_cmd := '${os.quoted_path(vexe)} ${verbose_flag} -g -o ${os.quoted_path(vdbg_path)} cmd/v' |
28 | vdbg_result := os.execute(vdbg_compilation_cmd) |
29 | os.chdir(wd) or {} |
30 | if vdbg_result.exit_code == 0 { |
31 | vexe = vdbg_path |
32 | } else { |
33 | eprintln('unable to compile V in debug mode: ${vdbg_result.output}\ncommand: ${vdbg_compilation_cmd}\n') |
34 | } |
35 | // |
36 | mut result := os.execute('${os.quoted_path(vexe)} ${verbose_flag} ${os.quoted_path(file_path)}') |
37 | defer { |
38 | os.rm(vdbg_path) or { |
39 | if is_verbose { |
40 | eprintln('unable to delete `vdbg`: ${err}') |
41 | } |
42 | } |
43 | } |
44 | if result.exit_code == 0 { |
45 | defer { |
46 | mut generated_file := file_path.all_before_last('.') |
47 | $if windows { |
48 | generated_file += '.exe' |
49 | } |
50 | os.rm(generated_file) or { |
51 | if is_verbose { |
52 | eprintln('unable to delete generated file: ${err}') |
53 | } |
54 | } |
55 | } |
56 | run := is_yes |
57 | || ask('It looks like the compilation went well, do you want to run the file?') |
58 | if run { |
59 | result = os.execute('${os.quoted_path(vexe)} ${verbose_flag} run ${os.quoted_path(file_path)}') |
60 | if result.exit_code == 0 && !is_yes { |
61 | confirm_or_exit('It looks like the file ran correctly as well, are you sure you want to continue?') |
62 | } |
63 | } |
64 | } |
65 | return result.output |
66 | } |
67 | |
68 | fn ask(msg string) bool { |
69 | prompt := os.input_opt('${msg} [Y/n] ') or { 'y' } |
70 | return prompt == '' || prompt[0].ascii_str().to_lower() != 'n' |
71 | } |
72 | |
73 | fn confirm_or_exit(msg string) { |
74 | if !ask(msg) { |
75 | exit(1) |
76 | } |
77 | } |
78 | |
79 | fn main() { |
80 | mut file_path := '' |
81 | mut is_verbose := false |
82 | mut is_yes := false |
83 | for arg in os.args[2..] { |
84 | match arg { |
85 | '-v' { |
86 | is_verbose = true |
87 | } |
88 | '-y' { |
89 | is_yes = true |
90 | } |
91 | else { |
92 | if !arg.ends_with('.v') && !arg.ends_with('.vsh') && !arg.ends_with('.vv') { |
93 | eprintln('unknown argument: `${arg}`') |
94 | exit(1) |
95 | } |
96 | if file_path != '' { |
97 | eprintln('only one V file can be submitted') |
98 | exit(1) |
99 | } |
100 | file_path = arg |
101 | } |
102 | } |
103 | } |
104 | if file_path == '' { |
105 | eprintln('v bug: no v file listed to report') |
106 | exit(1) |
107 | } |
108 | os.unsetenv('VCOLORS') |
109 | // collect error information |
110 | // output from `v doctor` |
111 | vdoctor_output := get_vdoctor_output(is_verbose) |
112 | // file content |
113 | file_content := os.read_file(file_path) or { |
114 | eprintln('unable to get file "${file_path}" content: ${err}') |
115 | '' |
116 | } |
117 | // output from `v -g -o vdbg cmd/v && vdbg file.v` |
118 | build_output := get_v_build_output(is_verbose, is_yes, file_path) |
119 | // ask the user if he wants to submit even after an error |
120 | if !is_yes && (vdoctor_output == '' || file_content == '' || build_output == '') { |
121 | confirm_or_exit('An error occurred retrieving the information, do you want to continue?') |
122 | } |
123 | |
124 | expected_result := readline.read_line('What did you expect to see? ') or { |
125 | // Ctrl-C was pressed |
126 | eprintln('\nCanceled') |
127 | exit(1) |
128 | } |
129 | // open prefilled issue creation page, or print link as a fallback |
130 | |
131 | if !is_yes && vdoctor_output.contains('behind V master') { |
132 | 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?') |
133 | } |
134 | |
135 | // When updating this template, make sure to update `.github/ISSUE_TEMPLATE/bug_report.md` too |
136 | raw_body := '<!-- It is advisable to update all relevant modules using `v outdated` and `v install` --> |
137 | **V doctor:** |
138 | ``` |
139 | ${vdoctor_output} |
140 | ``` |
141 | |
142 | **What did you do?** |
143 | `v -g -o vdbg cmd/v && vdbg ${file_path}` |
144 | {file_content} |
145 | |
146 | **What did you expect to see?** |
147 | |
148 | ${expected_result} |
149 | |
150 | **What did you see instead?** |
151 | ``` |
152 | ${build_output}```' |
153 | mut encoded_body := urllib.query_escape(raw_body.replace_once('{file_content}', '```v\n${file_content}\n```')) |
154 | mut generated_uri := 'https://github.com/vlang/v/issues/new?labels=Bug&body=${encoded_body}' |
155 | if generated_uri.len > 8192 { |
156 | // GitHub doesn't support URLs longer than 8192 characters |
157 | encoded_body = urllib.query_escape(raw_body.replace_once('{file_content}', 'See attached file `${file_path}`')) |
158 | generated_uri = 'https://github.com/vlang/v/issues/new?labels=Bug&body=${encoded_body}' |
159 | println('Your file is too big to be submitted. Head over to the following URL and attach your file.') |
160 | println(generated_uri) |
161 | } else { |
162 | os.open_uri(generated_uri) or { |
163 | if is_verbose { |
164 | eprintln(err) |
165 | } |
166 | println(generated_uri) |
167 | } |
168 | } |
169 | } |