From 3a435fab682583d9b816358cbdc5d6e0484b5320 Mon Sep 17 00:00:00 2001 From: Laurent Cheylus Date: Sun, 18 Jan 2026 20:29:27 +0100 Subject: [PATCH] tools: add support for vgit-fmt-hook on OpenBSD (fix #26344) (#26388) --- cmd/tools/vgit-fmt-hook.v | 41 +++++++++++++++++++++++++++------- cmd/tools/vgit-fmt-hook_test.v | 31 ++++++++++++++++++++----- 2 files changed, 58 insertions(+), 14 deletions(-) diff --git a/cmd/tools/vgit-fmt-hook.v b/cmd/tools/vgit-fmt-hook.v index d9e9ec430..fd7eaa98a 100644 --- a/cmd/tools/vgit-fmt-hook.v +++ b/cmd/tools/vgit-fmt-hook.v @@ -4,12 +4,23 @@ import crypto.sha256 const vexe = os.getenv_opt('VEXE') or { panic('missing VEXE env variable') } const vroot = os.to_slash(os.real_path(os.dir(vexe))) const horiginal = os.to_slash(os.join_path(vroot, 'cmd/tools/git_pre_commit_hook.vsh')) +const shoriginal = os.join_path(os.vtmp_dir(), 'git_pre_commit_hook.sh') fn get_hook_target(git_folder string) string { return os.to_slash(os.join_path(git_folder, 'hooks/pre-commit')) } fn main() { + // On OS without support for 'env -S', generate shell script + // to run cmd/tools/git_pre_commit_hook.vsh + // TODO: detect other OS (BusyBox) without support for 'env -S' + $if openbsd { + os.write_file(shoriginal, '#!/bin/sh\nv run ${horiginal}') or { + eprintln('unable to write shell script ${shoriginal}') + exit(1) + } + os.chmod(shoriginal, 0o755)! + } git_folder := find_nearest_top_level_folder_with_a_git_subfolder(os.getwd()) or { eprintln('This command has to be run inside a Git repository.') exit(0) @@ -39,9 +50,15 @@ fn cmd_status(htarget string) { } fn cmd_install(htarget string) { - report_status(htarget, false) + if report_status(htarget, false) { + return + } println('> Installing the newest version of ${horiginal} over ${htarget} ...') - os.cp(horiginal, htarget) or { err_exit('failed to copy to ${htarget}') } + $if openbsd { + os.cp(shoriginal, htarget) or { err_exit('failed to copy to ${htarget}') } + } $else { + os.cp(horiginal, htarget) or { err_exit('failed to copy to ${htarget}') } + } println('> Done.') } @@ -55,25 +72,32 @@ fn cmd_remove(htarget string) { println('> Done.') } -fn report_status(htarget string, show_instructions bool) { - ostat := os.stat(horiginal) or { os.Stat{} } +// Returns true if pre-commit Git hook already exists and identical to VSH script +fn report_status(htarget string, show_instructions bool) bool { + mut original := '' + $if openbsd { + original = shoriginal + } $else { + original = horiginal + } + ostat := os.stat(original) or { os.Stat{} } tstat := os.stat(htarget) or { os.Stat{} } - ohash := hash_file(horiginal) or { '' } + ohash := hash_file(original) or { '' } thash := hash_file(htarget) or { '' } if os.exists(htarget) && os.is_file(htarget) { println('> CURRENT git repo pre-commit hook: size: ${tstat.size:6} bytes, sha256: ${thash}, ${htarget}') } else { println('> CURRENT git repo pre-commit hook: missing ${htarget}') } - if os.exists(horiginal) && os.is_file(horiginal) { - println('> Main V repo pre-commit hook script: size: ${ostat.size:6} bytes, sha256: ${ohash}, ${horiginal}') + if os.exists(original) && os.is_file(original) { + println('> Main V repo pre-commit hook script: size: ${ostat.size:6} bytes, sha256: ${ohash}, ${original}') } if ohash == thash { println('> Both files are exactly the same.') if show_instructions { show_msg_about_removing(htarget) } - return + return true } println('> Files have different hashes.') if ohash != '' && thash != '' { @@ -88,6 +112,7 @@ fn report_status(htarget string, show_instructions bool) { println('> with the newest pre-commit formatting script from the main V repo.') show_msg_about_removing(htarget) } + return false } fn show_msg_about_removing(htarget string) { diff --git a/cmd/tools/vgit-fmt-hook_test.v b/cmd/tools/vgit-fmt-hook_test.v index 68d67f23c..a57d22f07 100644 --- a/cmd/tools/vgit-fmt-hook_test.v +++ b/cmd/tools/vgit-fmt-hook_test.v @@ -5,7 +5,12 @@ const tfolder = os.to_slash(os.join_path(os.vtmp_dir(), 'fmt_hook_test')) const unformatted_content = ' fn main() {\nprintln( "hi" )\n println ( 123 )\n }' const formatted_content = "fn main() {\n\tprintln('hi')\n\tprintln(123)\n}\n" const hook_file = '.git/hooks/pre-commit' -const foreign_script = '#!/usr/bin/env -S v -raw-vsh-tmp-prefix tmp\nprintln("hello hello")' +// 'env -S' not supported on OpenBSD +$if openbsd { + const foreign_script = '#!/bin/sh\ncat < CURRENT git repo pre-commit hook: missing') assert res.output.contains('> Main V repo pre-commit hook script: size: ') - assert res.output.contains('cmd/tools/git_pre_commit_hook.vsh') + // Git hook = shell script on OpenBSD + $if openbsd { + assert res.output.contains('git_pre_commit_hook.sh') + } $else { + assert res.output.contains('cmd/tools/git_pre_commit_hook.vsh') + } assert res.output.contains('> Files have different hashes.') assert res.output.contains('> Use `v git-fmt-hook install`') } @@ -91,7 +101,12 @@ fn test_run_git_fmt_hook_status_explicit() { assert res.exit_code == 0 assert res.output.contains('> CURRENT git repo pre-commit hook: missing') assert res.output.contains('> Main V repo pre-commit hook script: size: ') - assert res.output.contains('cmd/tools/git_pre_commit_hook.vsh') + // Git hook = shell script on OpenBSD + $if openbsd { + assert res.output.contains('git_pre_commit_hook.sh') + } $else { + assert res.output.contains('cmd/tools/git_pre_commit_hook.vsh') + } assert res.output.contains('> Files have different hashes.') assert res.output.contains('> Use `v git-fmt-hook install`') } @@ -108,7 +123,12 @@ fn test_run_git_fmt_hook_install() { res := os.execute_or_exit('${os.quoted_path(vexe)} git-fmt-hook status') assert res.output.contains('> CURRENT git repo pre-commit hook: size: ') assert res.output.contains('> Main V repo pre-commit hook script: size: ') - assert res.output.contains('cmd/tools/git_pre_commit_hook.vsh') + // Git hook = shell script on OpenBSD + $if openbsd { + assert res.output.contains('git_pre_commit_hook.sh') + } $else { + assert res.output.contains('cmd/tools/git_pre_commit_hook.vsh') + } assert res.output.contains(hook_file) assert res.output.contains('> Both files are exactly the same.') assert !res.output.contains('> Use `v git-fmt-hook install`') @@ -124,7 +144,6 @@ fn test_run_git_fmt_hook_install() { assert dres.output.contains("+\tprintln('hi')") second := os.execute_or_exit('${os.quoted_path(vexe)} git-fmt-hook install') assert second.exit_code == 0 - assert second.output.contains('> Done.'), 'second:\n${second}' } fn test_run_git_fmt_hook_remove() { -- 2.39.5