From a458adefb789f8167360f93f537a8d40f85ad08b Mon Sep 17 00:00:00 2001 From: Turiiya <34311583+ttytm@users.noreply.github.com> Date: Thu, 4 Apr 2024 04:26:11 +0200 Subject: [PATCH] v.utils: update `githash` to be able to get the githash of every passed project (#21178) --- cmd/tools/vup.v | 4 +- vlib/v/checker/checker.v | 3 +- vlib/v/util/version/version.c.v | 75 ++++++++++++------------------ vlib/v/util/version/version_test.v | 38 +++++++++++++++ 4 files changed, 71 insertions(+), 49 deletions(-) create mode 100644 vlib/v/util/version/version_test.v diff --git a/cmd/tools/vup.v b/cmd/tools/vup.v index 4165ce2fc5..fcb372bd28 100644 --- a/cmd/tools/vup.v +++ b/cmd/tools/vup.v @@ -35,8 +35,8 @@ fn main() { os.chdir(app.vroot)! println('Updating V...') app.update_from_master() - v_hash := version.githash(false) - current_hash := version.githash(true) + v_hash := @VCURRENTHASH + current_hash := version.githash(vroot) or { v_hash } // println(v_hash) // println(current_hash) if v_hash == current_hash && !app.skip_current { diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index dfd1dea3a0..b23f3f0994 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -149,7 +149,8 @@ pub fn new_checker(table &ast.Table, pref_ &pref.Preferences) &Checker { pref: pref_ timers: util.new_timers(should_print: timers_should_print, label: 'checker') match_exhaustive_cutoff_limit: pref_.checker_match_exhaustive_cutoff_limit - v_current_commit_hash: version.githash(pref_.building_v) + v_current_commit_hash: if pref_.building_v { version.githash(pref_.vroot) or { + @VCURRENTHASH} } else { @VCURRENTHASH } } checker.comptime = &comptime.ComptimeInfo{ resolver: checker diff --git a/vlib/v/util/version/version.c.v b/vlib/v/util/version/version.c.v index 7575fcb456..e0d09610a0 100644 --- a/vlib/v/util/version/version.c.v +++ b/vlib/v/util/version/version.c.v @@ -17,7 +17,7 @@ pub fn vhash() string { pub fn full_hash() string { build_hash := vhash() - current_hash := githash(false) + current_hash := @VCURRENTHASH if build_hash == current_hash { return build_hash } @@ -29,52 +29,35 @@ 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}' + return 'V ${version.v_version} ${@VCURRENTHASH}' } -// 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. -// Note: 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 +// githash tries to find the current git commit hash for the specified +// project path by parsing the relevant files in its `.git/` folder. +pub fn githash(path string) !string { + // .git/HEAD + git_head_file := os.join_path(path, '.git', 'HEAD') + if !os.exists(git_head_file) { + return error('failed to find `${git_head_file}`') + } + // 'ref: refs/heads/master' ... the current branch name + head_content := os.read_file(git_head_file) or { + return error('failed to read `${git_head_file}`') + } + current_branch_hash := if head_content.starts_with('ref: ') { + rev_rel_path := head_content.replace('ref: ', '').trim_space() + rev_file := os.join_path(path, '.git', rev_rel_path) + // .git/refs/heads/master + if !os.exists(rev_file) { + return error('failed to find revision file `${rev_file}`') + } + // get the full commit hash contained in the ref heads file + os.read_file(rev_file) or { return error('failed to read revision file `${rev_file}`') } + } else { + head_content + } + desired_hash_length := 7 + return current_branch_hash[0..desired_hash_length] or { + error('failed to limit hash `${current_branch_hash}` to ${desired_hash_length} characters') } - - return @VCURRENTHASH } diff --git a/vlib/v/util/version/version_test.v b/vlib/v/util/version/version_test.v new file mode 100644 index 0000000000..c39e48be63 --- /dev/null +++ b/vlib/v/util/version/version_test.v @@ -0,0 +1,38 @@ +import v.util.version +import os + +fn test_githash() { + if !os.exists(os.join_path(@VMODROOT, '.git')) { + eprintln('> skipping test due to missing V .git directory') + return + } + sha := version.githash(@VMODROOT)! + assert sha == @VCURRENTHASH + + git_proj_path := os.join_path(os.vtmp_dir(), 'test_githash') + defer { + os.rmdir_all(git_proj_path) or {} + } + os.execute_opt('git init ${git_proj_path}')! + os.chdir(git_proj_path)! + if sha_ := version.githash(git_proj_path) { + assert false, 'Should not have found an unknown revision' + } else { + assert err.msg().contains('failed to find revision file'), err.msg() + } + os.execute_opt('git config user.name') or { + os.execute_opt('git config user.email "ci@vlang.io"')! + os.execute_opt('git config user.name "V CI"')! + } + os.write_file('v.mod', '')! + os.execute_opt('git add .')! + os.execute_opt('git commit -m "test1"')! + test_rev := os.execute_opt('git rev-parse --short HEAD')!.output.trim_space() + assert test_rev == version.githash(git_proj_path)! + os.write_file('README.md', '')! + os.execute_opt('git add .')! + os.execute_opt('git commit -m "test2"')! + test_rev2 := os.execute_opt('git rev-parse --short HEAD')!.output.trim_space() + assert test_rev2 != test_rev + assert test_rev2 == version.githash(git_proj_path)! +}