v.util: extract v.util.version, use it to speed up building `v repl`, `v up` and `v doctor`

pull/10978/head
Delyan Angelov 2021-07-27 12:35:54 +03:00
parent cb7be87d4e
commit 6134c4870b
No known key found for this signature in database
GPG Key ID: 66886C0F12D595ED
12 changed files with 134 additions and 122 deletions

View File

@ -6,7 +6,6 @@ import time
import term import term
import math import math
import scripting import scripting
import v.util
struct CmdResult { struct CmdResult {
mut: mut:
@ -127,8 +126,12 @@ fn new_aints(ovals []int, extreme_mins int, extreme_maxs int) Aints {
return res return res
} }
fn bold(s string) string {
return term.colorize(term.bold, s)
}
fn (a Aints) str() string { 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}' '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 = ' ' first_marker = ' '
cpercent := (r.atiming.average / base) * 100 - 100 cpercent := (r.atiming.average / base) * 100 - 100
if r.icmd == 0 { if r.icmd == 0 {
first_marker = util.bold('>') first_marker = bold('>')
first_cmd_percentage = cpercent first_cmd_percentage = cpercent
} }
println(' $first_marker${(i + 1):3} | ${cpercent:5.1f}% slower | ${r.cmd:-57s} | $r.atiming') println(' $first_marker${(i + 1):3} | ${cpercent:5.1f}% slower | ${r.cmd:-57s} | $r.atiming')

View File

@ -1,6 +1,7 @@
import os import os
import time import time
import v.util import term
import v.util.version
import runtime import runtime
struct App { 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('vexe mtime', time.unix(os.file_last_mod_unix(vexe)).str())
a.line('is vroot writable', is_writable_dir(vroot).str()) a.line('is vroot writable', is_writable_dir(vroot).str())
a.line('is vmodules writable', is_writable_dir(vmodules).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') vtmp := os.getenv('VTMP')
if vtmp != '' { if vtmp != '' {
a.line('env VTMP', '"$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) { 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 { fn (app &App) parse(config string, sep string) map[string]string {

View File

@ -8,7 +8,7 @@ import term
import rand import rand
import readline import readline
import os.cmdline import os.cmdline
import v.util import v.util.version
struct Repl { struct Repl {
mut: mut:
@ -102,7 +102,7 @@ fn (r &Repl) current_source_code(should_add_temp_lines bool, not_add_print bool)
} }
fn repl_help() { fn repl_help() {
println(util.full_v_version(false)) println(version.full_v_version(false))
println(' println('
|help Displays this information. |help Displays this information.
|list Show the program so far. |list Show the program so far.
@ -114,8 +114,8 @@ fn repl_help() {
fn run_repl(workdir string, vrepl_prefix string) { fn run_repl(workdir string, vrepl_prefix string) {
if !is_stdin_a_pipe { if !is_stdin_a_pipe {
println(util.full_v_version(false)) println(version.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('Use Ctrl-C or ${term.highlight_command('exit')} to exit, or ${term.highlight_command('help')} to see other available commands')
} }
if vstartup != '' { if vstartup != '' {

View File

@ -2,7 +2,7 @@ module main
import os import os
import v.pref import v.pref
import v.util import v.util.version
import v.util.recompilation import v.util.recompilation
struct App { struct App {
@ -29,8 +29,8 @@ fn main() {
os.chdir(app.vroot) os.chdir(app.vroot)
println('Updating V...') println('Updating V...')
app.update_from_master() app.update_from_master()
v_hash := util.githash(false) v_hash := version.githash(false)
current_hash := util.githash(true) current_hash := version.githash(true)
// println(v_hash) // println(v_hash)
// println(current_hash) // println(current_hash)
if v_hash == current_hash { if v_hash == current_hash {

View File

@ -5,8 +5,10 @@ module main
import help import help
import os import os
import term
import v.pref import v.pref
import v.util import v.util
import v.util.version
import v.builder import v.builder
const ( const (
@ -60,10 +62,10 @@ fn main() {
// Running `./v` without args launches repl // Running `./v` without args launches repl
if args.len == 0 { if args.len == 0 {
if os.is_atty(0) != 0 { if os.is_atty(0) != 0 {
cmd_exit := util.pretty_print('exit') cmd_exit := term.highlight_command('exit')
cmd_help := util.pretty_print('v help') cmd_help := term.highlight_command('v help')
file_main := util.pretty_print('main.v') file_main := term.highlight_command('main.v')
cmd_run := util.pretty_print('v run 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).') 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(' 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') eprintln(' save your code in a $file_main file and execute: $cmd_run')
@ -114,7 +116,7 @@ fn main() {
exit(1) exit(1)
} }
'version' { 'version' {
println(util.full_v_version(prefs.is_verbose)) println(version.full_v_version(prefs.is_verbose))
return return
} }
else {} else {}
@ -128,7 +130,7 @@ fn main() {
if prefs.is_help { if prefs.is_help {
invoke_help_and_exit(args) 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) exit(1)
} }
@ -138,7 +140,7 @@ fn invoke_help_and_exit(remaining []string) {
2 { help.print_and_exit(remaining[1]) } 2 { help.print_and_exit(remaining[1]) }
else {} else {}
} }
println('${util.pretty_print('v help')}: provide only one help topic.') println('${term.highlight_command('v help')}: provide only one help topic.')
println('For usage information, use ${util.pretty_print('v help')}.') println('For usage information, use ${term.highlight_command('v help')}.')
exit(1) exit(1)
} }

View File

@ -191,3 +191,9 @@ pub fn yellow(msg string) string {
pub fn bright_yellow(msg string) string { pub fn bright_yellow(msg string) string {
return format(msg, '93', '39') 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 '))
}

View File

@ -10,6 +10,7 @@ import v.vmod
import v.token import v.token
import v.pref import v.pref
import v.util import v.util
import v.util.version
import v.errors import v.errors
import v.pkgconfig import v.pkgconfig
import v.gen.native 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() node.val = (node.pos.col + 1).str()
} }
.vhash { .vhash {
node.val = util.vhash() node.val = version.vhash()
} }
.vmod_file { .vmod_file {
// cache the vmod content, do not read it many times // cache the vmod content, do not read it many times

View File

@ -9,6 +9,7 @@ import v.ast
import v.pref import v.pref
import v.token import v.token
import v.util import v.util
import v.util.version
import v.depgraph import v.depgraph
const ( const (
@ -389,8 +390,8 @@ pub fn gen(files []&ast.File, table &ast.Table, pref &pref.Preferences) string {
} }
pub fn (g &Gen) hashes() string { pub fn (g &Gen) hashes() string {
mut res := c_commit_hash_default.replace('@@@', util.vhash()) mut res := c_commit_hash_default.replace('@@@', version.vhash())
res += c_current_commit_hash_default.replace('@@@', util.githash(g.pref.building_v)) res += c_current_commit_hash_default.replace('@@@', version.githash(g.pref.building_v))
return res return res
} }

View File

@ -5,6 +5,7 @@ import v.ast
import v.token import v.token
import v.pref import v.pref
import v.util import v.util
import v.util.version
import v.depgraph import v.depgraph
import encoding.base64 import encoding.base64
import v.gen.js.sourcemap import v.gen.js.sourcemap
@ -329,8 +330,8 @@ pub fn (mut g JsGen) init() {
} }
pub fn (g JsGen) hashes() string { pub fn (g JsGen) hashes() string {
mut res := '// V_COMMIT_HASH $util.vhash()\n' mut res := '// V_COMMIT_HASH $version.vhash()\n'
res += '// V_CURRENT_COMMIT_HASH ${util.githash(g.pref.building_v)}\n' res += '// V_CURRENT_COMMIT_HASH ${version.githash(g.pref.building_v)}\n'
return res return res
} }

View File

@ -1,11 +1,14 @@
import os import os
import term import term
import benchmark import benchmark
import v.util
import v.util.vtest import v.util.vtest
const turn_off_vcolors = os.setenv('VCOLORS', 'never', true) 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. // 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 // .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' exe_filename := '$wrkdir/x'
full_path_to_source_file := os.join_path(vroot, test) 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"' 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) res := os.execute(compile_cmd)
if res.exit_code != 0 { if res.exit_code != 0 {
bench.fail() bench.fail()
@ -89,11 +92,11 @@ fn test_all() {
} }
} }
valgrind_cmd := 'valgrind --error-exitcode=1 --leak-check=full $exe_filename' 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) valgrind_res := os.execute(valgrind_cmd)
if valgrind_res.exit_code != 0 { if valgrind_res.exit_code != 0 {
bench.fail() 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(valgrind_res.output)
eprintln('You can reproduce the failure with:\n$compile_cmd && $valgrind_cmd') eprintln('You can reproduce the failure with:\n$compile_cmd && $valgrind_cmd')
continue continue

View File

@ -5,15 +5,10 @@ module util
import os import os
import time import time
import term
import v.pref import v.pref
import v.vmod import v.vmod
import v.util.recompilation import v.util.recompilation
pub const (
v_version = '0.2.2'
)
// math.bits is needed by strconv.ftoa // math.bits is needed by strconv.ftoa
pub const ( pub const (
builtin_module_parts = ['math.bits', 'strconv', 'strconv.ftoa', 'strings', 'builtin'] 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) } 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) { pub fn set_vroot_folder(vroot_path string) {
// Preparation for the compiler module: // 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 { for emodule in emodules {
check_module_is_installed(emodule, is_verbose) or { panic(err) } 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'] { if tool_name in ['vself', 'vup', 'vdoctor', 'vsymlink'] {
// These tools will be called by users in cases where there // These tools will be called by users in cases where there
// is high chance of there being a problem somewhere. Thus // 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 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 '))
}

View File

@ -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)
}
}