v / cmd / tools / vdoc / run_examples.v
91 lines · 85 sloc · 3.03 KB · 8e35f4d9848f7ad35d857a187dddbfd2eca5e19d
Raw
1module main
2
3import document as doc
4import v.vmod
5import os
6import rand
7import term
8
9fn (mut vd VDoc) process_all_examples(contents []doc.DocNode) {
10 for cn in contents {
11 if cn.content.len > 0 {
12 vd.run_examples(cn)
13 }
14 vd.process_all_examples(cn.children)
15 }
16}
17
18const normalised_default_vmodules_path = os.vmodules_dir().replace('\\', '/')
19const vdoc_max_fails = os.getenv_opt('VDOC_MAX_FAILS') or { '999' }.int()
20
21fn get_mod_name_by_file_path(file_path string) string {
22 mut mcache := vmod.get_cache()
23 dn_folder := os.dir(os.real_path(file_path)).replace('\\', '/').trim_string_right('/src')
24 vmodpath := mcache.get_by_folder(dn_folder)
25 normal_folder := dn_folder.replace('\\', '/')
26 vmod_folder := vmodpath.vmod_folder.replace('\\', '/')
27 mut relative_mod_path := normal_folder
28 relative_mod_path = relative_mod_path.trim_string_left(vmod_folder).trim_string_left('/')
29 relative_mod_path = relative_mod_path.trim_string_left(normalised_default_vmodules_path)
30 relative_mod_path = relative_mod_path.trim_string_left('vlib/')
31 mod_name := relative_mod_path.replace('/', '.').trim('.')
32 return mod_name
33}
34
35fn (mut vd VDoc) run_examples(dn doc.DocNode) {
36 if dn.comments.len == 0 || vd.cfg.run_examples == .skip {
37 return
38 }
39 voptions := match vd.cfg.run_examples {
40 .run { ' -g run ' }
41 .check { '-N -W -check' }
42 .skip { '' }
43 }
44
45 examples := dn.examples()
46 if examples.len == 0 {
47 return
48 }
49 efolder := os.vtmp_dir()
50 mut example_program_source_files := []string{}
51 defer {
52 for sfile in example_program_source_files {
53 os.rm(sfile) or {}
54 }
55 }
56 for example in examples {
57 if vd.example_failures >= vdoc_max_fails {
58 eprintln('> vdoc: too many examples failed in ${vd.cfg.run_examples} mode')
59 exit(1)
60 }
61 code := example.all_after('Example:').all_after('example:').trim_space()
62 mod_name := get_mod_name_by_file_path(dn.file_path)
63 vsource_path := os.join_path(efolder, 'example_${rand.ulid()}.v')
64 // eprintln('>>> example dn.file_path: ${dn.file_path} | mod_name: ${mod_name} | vsource_path: ${vsource_path} | code: `${code}`')
65 import_clause := if mod_name in ['builtin', ''] { '' } else { 'import ${mod_name}\n' }
66 mut source := if import_clause != '' && !code.contains('import ') {
67 '${import_clause}fn main() {\n\t${code}\n}\n'
68 } else {
69 code
70 }
71 if !source.ends_with('\n') {
72 source += '\n'
73 }
74 os.write_file(vsource_path, source) or { continue }
75 vd.vprintln('>>> vd.example_oks: ${vd.example_oks:5} | vd.example_failures: ${vd.example_failures:5} | examples.len: ${examples.len} | source.len: ${source.len:5} | dn.name: ${dn.name}')
76 cmd := '${os.quoted_path(vexe)} ${voptions} ${os.quoted_path(vsource_path)}'
77 res := os.execute(cmd)
78 if res.exit_code != 0 {
79 eprintln('${dn_to_location(dn)}:${term.ecolorize(term.red,
80 'error in documentation example')}')
81 eprintln(' cmd: ${cmd}')
82 eprintln(' example line: ${term.colorize(term.bright_yellow, example)}')
83 eprintln(' result:')
84 eprintln(res.output)
85 vd.example_failures++
86 continue
87 }
88 example_program_source_files << vsource_path
89 vd.example_oks++
90 }
91}
92