| 1 | module main |
| 2 | |
| 3 | import document as doc |
| 4 | import v.vmod |
| 5 | import os |
| 6 | import rand |
| 7 | import term |
| 8 | |
| 9 | fn (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 | |
| 18 | const normalised_default_vmodules_path = os.vmodules_dir().replace('\\', '/') |
| 19 | const vdoc_max_fails = os.getenv_opt('VDOC_MAX_FAILS') or { '999' }.int() |
| 20 | |
| 21 | fn 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 | |
| 35 | fn (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 | |