From 084f853a2a8a04dac4f50b05e4aa3b1258908993 Mon Sep 17 00:00:00 2001 From: Delyan Angelov Date: Thu, 2 Apr 2020 14:31:02 +0300 Subject: [PATCH] v2: enhance version with current git commit hash. Cleanup redundant code. --- cmd/tools/vrepl.v | 13 ++---- cmd/v/internal/compile/cc.v | 18 ++------ cmd/v/v.v | 18 ++------ vlib/v/gen/cgen.v | 9 +++- vlib/v/gen/cheaders.v | 17 +++++++- vlib/v/scanner/scanner.v | 10 +---- vlib/v/util/util.v | 84 +++++++++++++++++++++++++++++++++++++ 7 files changed, 119 insertions(+), 50 deletions(-) create mode 100644 vlib/v/util/util.v diff --git a/cmd/tools/vrepl.v b/cmd/tools/vrepl.v index c55e679bf7..fe9006fd39 100644 --- a/cmd/tools/vrepl.v +++ b/cmd/tools/vrepl.v @@ -9,6 +9,7 @@ import ( term readline os.cmdline + v.util ) struct Repl { @@ -63,8 +64,7 @@ fn (r &Repl) function_call(line string) bool { } pub fn repl_help() { - version := v_version() - println(version) + println(util.full_v_version()) println(' help Displays this information. Ctrl-C, Ctrl-D, exit Exits the REPL. @@ -73,8 +73,7 @@ pub fn repl_help() { } pub fn run_repl(workdir string, vrepl_prefix string) []string { - version := v_version() - println(version) + println(util.full_v_version()) println('Use Ctrl-C or `exit` to exit') file := os.join_path(workdir, '.${vrepl_prefix}vrepl.v') @@ -233,9 +232,3 @@ pub fn rerror(s string) { os.flush() exit(1) } - -fn v_version() string { - vexe := os.getenv('VEXE') - vversion_res := os.exec('$vexe -version') or { panic('"$vexe -version" is not working') } - return vversion_res.output -} diff --git a/cmd/v/internal/compile/cc.v b/cmd/v/internal/compile/cc.v index e1b0970974..347b98179c 100644 --- a/cmd/v/internal/compile/cc.v +++ b/cmd/v/internal/compile/cc.v @@ -7,16 +7,12 @@ import ( os time v.pref + v.util term ) - pub const ( - v_version = '0.1.26' - ) - - const ( -v_modules_path = pref.default_module_path + v_modules_path = pref.default_module_path ) fn todo() { @@ -380,7 +376,7 @@ start: ================== C error. This should never happen. -V compiler version: V $v_version $vhash() +V compiler version: ${util.full_v_version()} Host OS: ${pref.get_host_os().str()} Target OS: $v.pref.os.str() @@ -626,11 +622,3 @@ fn error_context_lines(text, keyword string, before, after int) []string { idx_e := if idx_s + after < lines.len { idx_s + after } else { lines.len } return lines[idx_s..idx_e] } - -fn vhash() string { - mut buf := [50]byte - buf[0] = 0 - C.snprintf(charptr(buf), 50, '%s', C.V_COMMIT_HASH) - return tos_clone(buf) -} - diff --git a/cmd/v/v.v b/cmd/v/v.v index cada6b4c79..b6b28b29f4 100644 --- a/cmd/v/v.v +++ b/cmd/v/v.v @@ -11,6 +11,7 @@ import ( v.table v.doc v.pref + v.util ) const ( @@ -23,11 +24,6 @@ const ( 'setup-freetype'] ) - pub const ( - v_version = '0.1.26' - ) - - fn main() { prefs := flag.MainCmdPreferences{} values := flag.parse_main_cmd(os.args, parse_flags, prefs) or { @@ -36,7 +32,7 @@ fn main() { exit(1) } if prefs.verbosity.is_higher_or_equal(.level_two) { - println('V $v_version $vhash()') + println(util.full_v_version()) } if prefs.verbosity.is_higher_or_equal(.level_three) { println('Parsed preferences: ') @@ -126,18 +122,10 @@ fn main() { } fn print_version_and_exit() { - version_hash := vhash() - println('V $v_version $version_hash') + println(util.full_v_version()) exit(0) } -fn vhash() string { - mut buf := [50]byte - buf[0] = 0 - C.snprintf(charptr(buf), 50, '%s', C.V_COMMIT_HASH) - return tos_clone(buf) -} - fn invoke_help_and_exit(remaining []string) { match remaining.len { 0, 1 { diff --git a/vlib/v/gen/cgen.v b/vlib/v/gen/cgen.v index 1c7f103f61..6cebaacb2c 100644 --- a/vlib/v/gen/cgen.v +++ b/vlib/v/gen/cgen.v @@ -7,6 +7,7 @@ import ( v.depgraph v.token v.pref + v.util term ) @@ -98,7 +99,13 @@ pub fn cgen(files []ast.File, table &table.Table, pref &pref.Preferences) string if g.is_test { g.write_tests_main() } - return c_commit_hash_default + g.typedefs.str() + g.definitions.str() + g.out.str() + return g.hashes() + g.typedefs.str() + g.definitions.str() + g.out.str() +} + +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 ) ) + return res } pub fn (g mut Gen) init() { diff --git a/vlib/v/gen/cheaders.v b/vlib/v/gen/cheaders.v index 298f750a73..f7c99c0128 100644 --- a/vlib/v/gen/cheaders.v +++ b/vlib/v/gen/cheaders.v @@ -1,12 +1,27 @@ module gen +import v.util + +// NB: @@@ here serve as placeholders. +// They will be replaced with correct strings +// for each constant, during C code generation. + const ( + // V_COMMIT_HASH is generated by cmd/tools/gen_vc.v . c_commit_hash_default = ' #ifndef V_COMMIT_HASH -#define V_COMMIT_HASH "$vhash()" +#define V_COMMIT_HASH "@@@" #endif ' + // V_CURRENT_COMMIT_HASH is updated, when V is rebuilt inside a git repo. + c_current_commit_hash_default = ' +#ifndef V_CURRENT_COMMIT_HASH +#define V_CURRENT_COMMIT_HASH "@@@" +#endif + +' + c_common_macros = ' #define EMPTY_STRUCT_DECLARATION #define EMPTY_STRUCT_INITIALIZATION 0 diff --git a/vlib/v/scanner/scanner.v b/vlib/v/scanner/scanner.v index db496e2cb7..c092d4b9fb 100644 --- a/vlib/v/scanner/scanner.v +++ b/vlib/v/scanner/scanner.v @@ -7,6 +7,7 @@ import ( os v.token v.pref + v.util ) const ( @@ -593,7 +594,7 @@ pub fn (s mut Scanner) scan() token.Token { return s.new_token(.string, (s.current_column()).str()) } if name == 'VHASH' { - return s.new_token(.string, vhash()) + return s.new_token(.string, util.vhash()) } if !token.is_key(name) { s.error('@ must be used before keywords (e.g. `@type string`)') @@ -1033,13 +1034,6 @@ pub fn verror(s string) { exit(1) } -pub fn vhash() string { - mut buf := [50]byte - buf[0] = 0 - C.snprintf(charptr(buf), 50, '%s', C.V_COMMIT_HASH) - return tos_clone(buf) -} - pub fn cescaped_path(s string) string { return s.replace('\\', '\\\\') } diff --git a/vlib/v/util/util.v b/vlib/v/util/util.v new file mode 100644 index 0000000000..5718f525a4 --- /dev/null +++ b/vlib/v/util/util.v @@ -0,0 +1,84 @@ +// Copyright (c) 2019-2020 Alexander Medvednikov. All rights reserved. +// Use of this source code is governed by an MIT license +// that can be found in the LICENSE file. +module util + +import os + +pub const ( + v_version = '0.1.26' +) + +// 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 + C.snprintf(charptr(buf), 50, '%s', C.V_COMMIT_HASH) + return tos_clone(buf) +} + +pub fn full_hash() string { + build_hash := vhash() + current_hash := githash(false) + final_hash := if build_hash == current_hash { + build_hash + } else { + '${build_hash}.${current_hash}' + } + return final_hash +} + +// full_v_version() returns the full version of the V compiler +pub fn full_v_version() string { + return 'V ${v_version} ${full_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 + } + 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 + current_branch_hash := os.read_file( gcbranch_file ) or { + break + } + desired_hash_length := 7 + if current_branch_hash.len > desired_hash_length { + return current_branch_hash[0..desired_hash_length] + } + } + break + } + // TODO: use C.V_CURRENT_COMMIT_HASH at stage 2, after v.c is regenerated + // mut buf := [50]byte + // buf[0] = 0 + // C.snprintf(charptr(buf), 50, '%s', C.V_CURRENT_COMMIT_HASH) + // return tos_clone(buf) + return 'unknown' +}