From 6134c4870beeea4d7dd640a3f121e8aaf1703f92 Mon Sep 17 00:00:00 2001 From: Delyan Angelov Date: Tue, 27 Jul 2021 12:35:54 +0300 Subject: [PATCH] v.util: extract v.util.version, use it to speed up building `v repl`, `v up` and `v doctor` --- cmd/tools/repeat.v | 9 ++- cmd/tools/vdoctor.v | 7 +- cmd/tools/vrepl.v | 8 +-- cmd/tools/vup.v | 6 +- cmd/v/v.v | 18 +++--- vlib/term/colors.v | 6 ++ vlib/v/checker/checker.v | 3 +- vlib/v/gen/c/cgen.v | 5 +- vlib/v/gen/js/js.v | 5 +- vlib/v/tests/valgrind/valgrind_test.v | 11 ++-- vlib/v/util/util.v | 93 +-------------------------- vlib/v/util/version/version.v | 85 ++++++++++++++++++++++++ 12 files changed, 134 insertions(+), 122 deletions(-) create mode 100644 vlib/v/util/version/version.v diff --git a/cmd/tools/repeat.v b/cmd/tools/repeat.v index 6d65d190ec..e69cfdfde7 100644 --- a/cmd/tools/repeat.v +++ b/cmd/tools/repeat.v @@ -6,7 +6,6 @@ import time import term import math import scripting -import v.util struct CmdResult { mut: @@ -127,8 +126,12 @@ fn new_aints(ovals []int, extreme_mins int, extreme_maxs int) Aints { return res } +fn bold(s string) string { + return term.colorize(term.bold, s) +} + fn (a Aints) str() string { - return util.bold('${a.average:6.2f}') + + return bold('${a.average:6.2f}') + 'ms ± σ: ${a.stddev:4.1f}ms, min: ${a.imin:4}ms, max: ${a.imax:4}ms, runs:${a.values.len:3}, nmins:${a.nmins:2}, nmaxs:${a.nmaxs:2}' } @@ -346,7 +349,7 @@ fn (mut context Context) show_diff_summary() { first_marker = ' ' cpercent := (r.atiming.average / base) * 100 - 100 if r.icmd == 0 { - first_marker = util.bold('>') + first_marker = bold('>') first_cmd_percentage = cpercent } println(' $first_marker${(i + 1):3} | ${cpercent:5.1f}% slower | ${r.cmd:-57s} | $r.atiming') diff --git a/cmd/tools/vdoctor.v b/cmd/tools/vdoctor.v index 965f6afbb2..7eb8901342 100644 --- a/cmd/tools/vdoctor.v +++ b/cmd/tools/vdoctor.v @@ -1,6 +1,7 @@ import os import time -import v.util +import term +import v.util.version import runtime struct App { @@ -109,7 +110,7 @@ fn (mut a App) collect_info() { a.line('vexe mtime', time.unix(os.file_last_mod_unix(vexe)).str()) a.line('is vroot writable', is_writable_dir(vroot).str()) a.line('is vmodules writable', is_writable_dir(vmodules).str()) - a.line('V full version', util.full_v_version(true)) + a.line('V full version', version.full_v_version(true)) vtmp := os.getenv('VTMP') if vtmp != '' { a.line('env VTMP', '"$vtmp"') @@ -149,7 +150,7 @@ fn (mut a App) cmd(c CmdConfig) string { } fn (mut a App) line(label string, value string) { - a.println('$label: ${util.bold(value)}') + a.println('$label: ${term.colorize(term.bold, value)}') } fn (app &App) parse(config string, sep string) map[string]string { diff --git a/cmd/tools/vrepl.v b/cmd/tools/vrepl.v index 717798b81f..99ea224465 100644 --- a/cmd/tools/vrepl.v +++ b/cmd/tools/vrepl.v @@ -8,7 +8,7 @@ import term import rand import readline import os.cmdline -import v.util +import v.util.version struct Repl { mut: @@ -102,7 +102,7 @@ fn (r &Repl) current_source_code(should_add_temp_lines bool, not_add_print bool) } fn repl_help() { - println(util.full_v_version(false)) + println(version.full_v_version(false)) println(' |help Displays this information. |list Show the program so far. @@ -114,8 +114,8 @@ fn repl_help() { fn run_repl(workdir string, vrepl_prefix string) { if !is_stdin_a_pipe { - println(util.full_v_version(false)) - println('Use Ctrl-C or ${util.pretty_print('exit')} to exit, or ${util.pretty_print('help')} to see other available commands') + println(version.full_v_version(false)) + println('Use Ctrl-C or ${term.highlight_command('exit')} to exit, or ${term.highlight_command('help')} to see other available commands') } if vstartup != '' { diff --git a/cmd/tools/vup.v b/cmd/tools/vup.v index c642132907..db6684a7a7 100644 --- a/cmd/tools/vup.v +++ b/cmd/tools/vup.v @@ -2,7 +2,7 @@ module main import os import v.pref -import v.util +import v.util.version import v.util.recompilation struct App { @@ -29,8 +29,8 @@ fn main() { os.chdir(app.vroot) println('Updating V...') app.update_from_master() - v_hash := util.githash(false) - current_hash := util.githash(true) + v_hash := version.githash(false) + current_hash := version.githash(true) // println(v_hash) // println(current_hash) if v_hash == current_hash { diff --git a/cmd/v/v.v b/cmd/v/v.v index a61b762bb6..dde303d3e9 100644 --- a/cmd/v/v.v +++ b/cmd/v/v.v @@ -5,8 +5,10 @@ module main import help import os +import term import v.pref import v.util +import v.util.version import v.builder const ( @@ -60,10 +62,10 @@ fn main() { // Running `./v` without args launches repl if args.len == 0 { if os.is_atty(0) != 0 { - cmd_exit := util.pretty_print('exit') - cmd_help := util.pretty_print('v help') - file_main := util.pretty_print('main.v') - cmd_run := util.pretty_print('v run main.v') + cmd_exit := term.highlight_command('exit') + cmd_help := term.highlight_command('v help') + file_main := term.highlight_command('main.v') + cmd_run := term.highlight_command('v run main.v') println('Welcome to the V REPL (for help with V itself, type $cmd_exit, then run $cmd_help).') eprintln(' NB: the REPL is highly experimental. For best V experience, use a text editor,') eprintln(' save your code in a $file_main file and execute: $cmd_run') @@ -114,7 +116,7 @@ fn main() { exit(1) } 'version' { - println(util.full_v_version(prefs.is_verbose)) + println(version.full_v_version(prefs.is_verbose)) return } else {} @@ -128,7 +130,7 @@ fn main() { if prefs.is_help { invoke_help_and_exit(args) } - eprintln('v $command: unknown command\nRun ${util.pretty_print('v help')} for usage.') + eprintln('v $command: unknown command\nRun ${term.highlight_command('v help')} for usage.') exit(1) } @@ -138,7 +140,7 @@ fn invoke_help_and_exit(remaining []string) { 2 { help.print_and_exit(remaining[1]) } else {} } - println('${util.pretty_print('v help')}: provide only one help topic.') - println('For usage information, use ${util.pretty_print('v help')}.') + println('${term.highlight_command('v help')}: provide only one help topic.') + println('For usage information, use ${term.highlight_command('v help')}.') exit(1) } diff --git a/vlib/term/colors.v b/vlib/term/colors.v index 2fb0666c36..f7662eea31 100644 --- a/vlib/term/colors.v +++ b/vlib/term/colors.v @@ -191,3 +191,9 @@ pub fn yellow(msg string) string { pub fn bright_yellow(msg string) string { return format(msg, '93', '39') } + +// highlight_command highlights the command with an on-brand background +// to make CLI commands immediately recognizable. +pub fn highlight_command(command string) string { + return bright_white(bg_cyan(' $command ')) +} diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index 6e614cef61..2438d707b0 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -10,6 +10,7 @@ import v.vmod import v.token import v.pref import v.util +import v.util.version import v.errors import v.pkgconfig import v.gen.native @@ -5683,7 +5684,7 @@ fn (mut c Checker) at_expr(mut node ast.AtExpr) ast.Type { node.val = (node.pos.col + 1).str() } .vhash { - node.val = util.vhash() + node.val = version.vhash() } .vmod_file { // cache the vmod content, do not read it many times diff --git a/vlib/v/gen/c/cgen.v b/vlib/v/gen/c/cgen.v index 90574cfd0c..e093d7cfa7 100644 --- a/vlib/v/gen/c/cgen.v +++ b/vlib/v/gen/c/cgen.v @@ -9,6 +9,7 @@ import v.ast import v.pref import v.token import v.util +import v.util.version import v.depgraph const ( @@ -389,8 +390,8 @@ pub fn gen(files []&ast.File, table &ast.Table, pref &pref.Preferences) string { } pub fn (g &Gen) hashes() string { - mut res := c_commit_hash_default.replace('@@@', util.vhash()) - res += c_current_commit_hash_default.replace('@@@', util.githash(g.pref.building_v)) + mut res := c_commit_hash_default.replace('@@@', version.vhash()) + res += c_current_commit_hash_default.replace('@@@', version.githash(g.pref.building_v)) return res } diff --git a/vlib/v/gen/js/js.v b/vlib/v/gen/js/js.v index f3a95c79a3..574c0ce1bd 100644 --- a/vlib/v/gen/js/js.v +++ b/vlib/v/gen/js/js.v @@ -5,6 +5,7 @@ import v.ast import v.token import v.pref import v.util +import v.util.version import v.depgraph import encoding.base64 import v.gen.js.sourcemap @@ -329,8 +330,8 @@ pub fn (mut g JsGen) init() { } pub fn (g JsGen) hashes() string { - mut res := '// V_COMMIT_HASH $util.vhash()\n' - res += '// V_CURRENT_COMMIT_HASH ${util.githash(g.pref.building_v)}\n' + mut res := '// V_COMMIT_HASH $version.vhash()\n' + res += '// V_CURRENT_COMMIT_HASH ${version.githash(g.pref.building_v)}\n' return res } diff --git a/vlib/v/tests/valgrind/valgrind_test.v b/vlib/v/tests/valgrind/valgrind_test.v index 0f9f5f5eca..620c47ec39 100644 --- a/vlib/v/tests/valgrind/valgrind_test.v +++ b/vlib/v/tests/valgrind/valgrind_test.v @@ -1,11 +1,14 @@ import os import term import benchmark -import v.util import v.util.vtest const turn_off_vcolors = os.setenv('VCOLORS', 'never', true) +fn bold(s string) string { + return term.colorize(term.bold, s) +} + // // NB: skip_compile_files can be used for totally skipping .v files temporarily. // .v files in skip_valgrind_files will be compiled, but will not be run under @@ -72,7 +75,7 @@ fn test_all() { exe_filename := '$wrkdir/x' full_path_to_source_file := os.join_path(vroot, test) compile_cmd := '$vexe -o $exe_filename -cg -cflags "-w" -autofree "$full_path_to_source_file"' - vprintln('compile cmd: ${util.bold(compile_cmd)}') + vprintln('compile cmd: ${bold(compile_cmd)}') res := os.execute(compile_cmd) if res.exit_code != 0 { bench.fail() @@ -89,11 +92,11 @@ fn test_all() { } } valgrind_cmd := 'valgrind --error-exitcode=1 --leak-check=full $exe_filename' - vprintln('valgrind cmd: ${util.bold(valgrind_cmd)}') + vprintln('valgrind cmd: ${bold(valgrind_cmd)}') valgrind_res := os.execute(valgrind_cmd) if valgrind_res.exit_code != 0 { bench.fail() - eprintln(bench.step_message_fail('failed valgrind check for ${util.bold(test)}')) + eprintln(bench.step_message_fail('failed valgrind check for ${bold(test)}')) eprintln(valgrind_res.output) eprintln('You can reproduce the failure with:\n$compile_cmd && $valgrind_cmd') continue diff --git a/vlib/v/util/util.v b/vlib/v/util/util.v index 2f54051f6a..e2f6d80cd7 100644 --- a/vlib/v/util/util.v +++ b/vlib/v/util/util.v @@ -5,15 +5,10 @@ module util import os import time -import term import v.pref import v.vmod import v.util.recompilation -pub const ( - v_version = '0.2.2' -) - // math.bits is needed by strconv.ftoa pub const ( builtin_module_parts = ['math.bits', 'strconv', 'strconv.ftoa', 'strings', 'builtin'] @@ -45,86 +40,6 @@ pub fn tabs(n int) string { return if n < util.const_tabs.len { util.const_tabs[n] } else { '\t'.repeat(n) } } -// vhash() returns the build string C.V_COMMIT_HASH . See cmd/tools/gen_vc.v . -pub fn vhash() string { - mut buf := [50]byte{} - buf[0] = 0 - unsafe { - bp := &buf[0] - C.snprintf(&char(bp), 50, c'%s', C.V_COMMIT_HASH) - return tos_clone(bp) - } -} - -pub fn full_hash() string { - build_hash := vhash() - current_hash := githash(false) - if build_hash == current_hash { - return build_hash - } - return '${build_hash}.$current_hash' -} - -// full_v_version() returns the full version of the V compiler -pub fn full_v_version(is_verbose bool) string { - if is_verbose { - return 'V $util.v_version $full_hash()' - } - hash := githash(false) - return 'V $util.v_version $hash' -} - -// githash(x) returns the current git commit hash. -// When x is false, it is very fast - it just returns a predefined C constant. -// When x is true, it tries to get the current commit hash, by parsing the -// relevant files in the .git/ folder, or if that is not possible -// for example when using a V from a V binary release, that does not have .git/ -// defaults to getting the predefined C constant again. -// NB: githash(true) must be called only when v detects that it builds itself. -// For all other programs, githash(false) should be used. -pub fn githash(should_get_from_filesystem bool) string { - for { - // The `for` construct here is used as a goto substitute. - // The code in this function will break out of the `for` - // if it detects an error and can not continue. - if should_get_from_filesystem { - vexe := os.getenv('VEXE') - vroot := os.dir(vexe) - // .git/HEAD - git_head_file := os.join_path(vroot, '.git', 'HEAD') - if !os.exists(git_head_file) { - break - } - // 'ref: refs/heads/master' ... the current branch name - head_content := os.read_file(git_head_file) or { break } - mut current_branch_hash := head_content - if head_content.starts_with('ref: ') { - gcbranch_rel_path := head_content.replace('ref: ', '').trim_space() - gcbranch_file := os.join_path(vroot, '.git', gcbranch_rel_path) - // .git/refs/heads/master - if !os.exists(gcbranch_file) { - break - } - // get the full commit hash contained in the ref heads file - branch_hash := os.read_file(gcbranch_file) or { break } - current_branch_hash = branch_hash - } - desired_hash_length := 7 - if current_branch_hash.len > desired_hash_length { - return current_branch_hash[0..desired_hash_length] - } - } - break - } - mut buf := [50]byte{} - buf[0] = 0 - unsafe { - bp := &buf[0] - C.snprintf(&char(bp), 50, c'%s', C.V_CURRENT_COMMIT_HASH) - return tos_clone(bp) - } -} - // pub fn set_vroot_folder(vroot_path string) { // Preparation for the compiler module: @@ -235,7 +150,7 @@ pub fn launch_tool(is_verbose bool, tool_name string, args []string) { for emodule in emodules { check_module_is_installed(emodule, is_verbose) or { panic(err) } } - mut compilation_command := '"$vexe" ' + mut compilation_command := '"$vexe" -skip-unused ' if tool_name in ['vself', 'vup', 'vdoctor', 'vsymlink'] { // These tools will be called by users in cases where there // is high chance of there being a problem somewhere. Thus @@ -570,9 +485,3 @@ pub fn find_all_v_files(roots []string) ?[]string { } return files } - -// Highlight a command with an on-brand background to make CLI -// commands immediately recognizable. -pub fn pretty_print(command string) string { - return term.bright_white(term.bg_cyan(' $command ')) -} diff --git a/vlib/v/util/version/version.v b/vlib/v/util/version/version.v new file mode 100644 index 0000000000..e266942881 --- /dev/null +++ b/vlib/v/util/version/version.v @@ -0,0 +1,85 @@ +module version + +import os + +pub const v_version = '0.2.2' + +// vhash() returns the build string C.V_COMMIT_HASH . See cmd/tools/gen_vc.v . +pub fn vhash() string { + mut buf := [50]byte{} + buf[0] = 0 + unsafe { + bp := &buf[0] + C.snprintf(&char(bp), 50, c'%s', C.V_COMMIT_HASH) + return tos_clone(bp) + } +} + +pub fn full_hash() string { + build_hash := vhash() + current_hash := githash(false) + if build_hash == current_hash { + return build_hash + } + return '${build_hash}.$current_hash' +} + +// full_v_version() returns the full version of the V compiler +pub fn full_v_version(is_verbose bool) string { + if is_verbose { + return 'V $version.v_version $full_hash()' + } + hash := githash(false) + return 'V $version.v_version $hash' +} + +// githash(x) returns the current git commit hash. +// When x is false, it is very fast - it just returns a predefined C constant. +// When x is true, it tries to get the current commit hash, by parsing the +// relevant files in the .git/ folder, or if that is not possible +// for example when using a V from a V binary release, that does not have .git/ +// defaults to getting the predefined C constant again. +// NB: githash(true) must be called only when v detects that it builds itself. +// For all other programs, githash(false) should be used. +pub fn githash(should_get_from_filesystem bool) string { + for { + // The `for` construct here is used as a goto substitute. + // The code in this function will break out of the `for` + // if it detects an error and can not continue. + if should_get_from_filesystem { + vexe := os.getenv('VEXE') + vroot := os.dir(vexe) + // .git/HEAD + git_head_file := os.join_path(vroot, '.git', 'HEAD') + if !os.exists(git_head_file) { + break + } + // 'ref: refs/heads/master' ... the current branch name + head_content := os.read_file(git_head_file) or { break } + mut current_branch_hash := head_content + if head_content.starts_with('ref: ') { + gcbranch_rel_path := head_content.replace('ref: ', '').trim_space() + gcbranch_file := os.join_path(vroot, '.git', gcbranch_rel_path) + // .git/refs/heads/master + if !os.exists(gcbranch_file) { + break + } + // get the full commit hash contained in the ref heads file + branch_hash := os.read_file(gcbranch_file) or { break } + current_branch_hash = branch_hash + } + desired_hash_length := 7 + if current_branch_hash.len > desired_hash_length { + return current_branch_hash[0..desired_hash_length] + } + } + break + } + mut buf := [50]byte{} + buf[0] = 0 + unsafe { + bp := &buf[0] + C.snprintf(&char(bp), 50, c'%s', C.V_CURRENT_COMMIT_HASH) + return tos_clone(bp) + } +}