Skip to content

Commit 3a435fa

Browse files
authored
tools: add support for vgit-fmt-hook on OpenBSD (fix #26344) (#26388)
1 parent d9eef4d commit 3a435fa

2 files changed

Lines changed: 58 additions & 14 deletions

File tree

‎cmd/tools/vgit-fmt-hook.v‎

Lines changed: 33 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,23 @@ import crypto.sha256
44
const vexe = os.getenv_opt('VEXE') or { panic('missing VEXE env variable') }
55
const vroot = os.to_slash(os.real_path(os.dir(vexe)))
66
const horiginal = os.to_slash(os.join_path(vroot, 'cmd/tools/git_pre_commit_hook.vsh'))
7+
const shoriginal = os.join_path(os.vtmp_dir(), 'git_pre_commit_hook.sh')
78

89
fn get_hook_target(git_folder string) string {
910
return os.to_slash(os.join_path(git_folder, 'hooks/pre-commit'))
1011
}
1112

1213
fn main() {
14+
// On OS without support for 'env -S', generate shell script
15+
// to run cmd/tools/git_pre_commit_hook.vsh
16+
// TODO: detect other OS (BusyBox) without support for 'env -S'
17+
$if openbsd {
18+
os.write_file(shoriginal, '#!/bin/sh\nv run ${horiginal}') or {
19+
eprintln('unable to write shell script ${shoriginal}')
20+
exit(1)
21+
}
22+
os.chmod(shoriginal, 0o755)!
23+
}
1324
git_folder := find_nearest_top_level_folder_with_a_git_subfolder(os.getwd()) or {
1425
eprintln('This command has to be run inside a Git repository.')
1526
exit(0)
@@ -39,9 +50,15 @@ fn cmd_status(htarget string) {
3950
}
4051

4152
fn cmd_install(htarget string) {
42-
report_status(htarget, false)
53+
if report_status(htarget, false) {
54+
return
55+
}
4356
println('> Installing the newest version of ${horiginal} over ${htarget} ...')
44-
os.cp(horiginal, htarget) or { err_exit('failed to copy to ${htarget}') }
57+
$if openbsd {
58+
os.cp(shoriginal, htarget) or { err_exit('failed to copy to ${htarget}') }
59+
} $else {
60+
os.cp(horiginal, htarget) or { err_exit('failed to copy to ${htarget}') }
61+
}
4562
println('> Done.')
4663
}
4764

@@ -55,25 +72,32 @@ fn cmd_remove(htarget string) {
5572
println('> Done.')
5673
}
5774

58-
fn report_status(htarget string, show_instructions bool) {
59-
ostat := os.stat(horiginal) or { os.Stat{} }
75+
// Returns true if pre-commit Git hook already exists and identical to VSH script
76+
fn report_status(htarget string, show_instructions bool) bool {
77+
mut original := ''
78+
$if openbsd {
79+
original = shoriginal
80+
} $else {
81+
original = horiginal
82+
}
83+
ostat := os.stat(original) or { os.Stat{} }
6084
tstat := os.stat(htarget) or { os.Stat{} }
61-
ohash := hash_file(horiginal) or { '' }
85+
ohash := hash_file(original) or { '' }
6286
thash := hash_file(htarget) or { '' }
6387
if os.exists(htarget) && os.is_file(htarget) {
6488
println('> CURRENT git repo pre-commit hook: size: ${tstat.size:6} bytes, sha256: ${thash}, ${htarget}')
6589
} else {
6690
println('> CURRENT git repo pre-commit hook: missing ${htarget}')
6791
}
68-
if os.exists(horiginal) && os.is_file(horiginal) {
69-
println('> Main V repo pre-commit hook script: size: ${ostat.size:6} bytes, sha256: ${ohash}, ${horiginal}')
92+
if os.exists(original) && os.is_file(original) {
93+
println('> Main V repo pre-commit hook script: size: ${ostat.size:6} bytes, sha256: ${ohash}, ${original}')
7094
}
7195
if ohash == thash {
7296
println('> Both files are exactly the same.')
7397
if show_instructions {
7498
show_msg_about_removing(htarget)
7599
}
76-
return
100+
return true
77101
}
78102
println('> Files have different hashes.')
79103
if ohash != '' && thash != '' {
@@ -88,6 +112,7 @@ fn report_status(htarget string, show_instructions bool) {
88112
println('> with the newest pre-commit formatting script from the main V repo.')
89113
show_msg_about_removing(htarget)
90114
}
115+
return false
91116
}
92117

93118
fn show_msg_about_removing(htarget string) {

‎cmd/tools/vgit-fmt-hook_test.v‎

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,12 @@ const tfolder = os.to_slash(os.join_path(os.vtmp_dir(), 'fmt_hook_test'))
55
const unformatted_content = ' fn main() {\nprintln( "hi" )\n println ( 123 )\n }'
66
const formatted_content = "fn main() {\n\tprintln('hi')\n\tprintln(123)\n}\n"
77
const hook_file = '.git/hooks/pre-commit'
8-
const foreign_script = '#!/usr/bin/env -S v -raw-vsh-tmp-prefix tmp\nprintln("hello hello")'
8+
// 'env -S' not supported on OpenBSD
9+
$if openbsd {
10+
const foreign_script = '#!/bin/sh\ncat <<EOF | ${vexe} run -\nprintln("hello hello")\nEOF'
11+
} $else {
12+
const foreign_script = '#!/usr/bin/env -S v -raw-vsh-tmp-prefix tmp\nprintln("hello hello")'
13+
}
914

1015
const git = os.to_slash(os.find_abs_path_of_executable('git') or {
1116
eprintln('git is needed for this test, skipping...')
@@ -35,7 +40,7 @@ fn testsuite_begin() {
3540
os.execute_or_exit('git commit -m "start testing, initially unformatted"')
3641
os.execute_or_exit('git checkout -b start') // use a known name, instead of master or main or who knows what else ...
3742
assert read_file('main.v') == unformatted_content
38-
// show_git_status()
43+
// show_git_status()
3944
}
4045

4146
fn testsuite_end() {
@@ -79,7 +84,12 @@ fn test_run_git_fmt_hook() {
7984
assert res.exit_code == 0
8085
assert res.output.contains('> CURRENT git repo pre-commit hook: missing')
8186
assert res.output.contains('> Main V repo pre-commit hook script: size: ')
82-
assert res.output.contains('cmd/tools/git_pre_commit_hook.vsh')
87+
// Git hook = shell script on OpenBSD
88+
$if openbsd {
89+
assert res.output.contains('git_pre_commit_hook.sh')
90+
} $else {
91+
assert res.output.contains('cmd/tools/git_pre_commit_hook.vsh')
92+
}
8393
assert res.output.contains('> Files have different hashes.')
8494
assert res.output.contains('> Use `v git-fmt-hook install`')
8595
}
@@ -91,7 +101,12 @@ fn test_run_git_fmt_hook_status_explicit() {
91101
assert res.exit_code == 0
92102
assert res.output.contains('> CURRENT git repo pre-commit hook: missing')
93103
assert res.output.contains('> Main V repo pre-commit hook script: size: ')
94-
assert res.output.contains('cmd/tools/git_pre_commit_hook.vsh')
104+
// Git hook = shell script on OpenBSD
105+
$if openbsd {
106+
assert res.output.contains('git_pre_commit_hook.sh')
107+
} $else {
108+
assert res.output.contains('cmd/tools/git_pre_commit_hook.vsh')
109+
}
95110
assert res.output.contains('> Files have different hashes.')
96111
assert res.output.contains('> Use `v git-fmt-hook install`')
97112
}
@@ -108,7 +123,12 @@ fn test_run_git_fmt_hook_install() {
108123
res := os.execute_or_exit('${os.quoted_path(vexe)} git-fmt-hook status')
109124
assert res.output.contains('> CURRENT git repo pre-commit hook: size: ')
110125
assert res.output.contains('> Main V repo pre-commit hook script: size: ')
111-
assert res.output.contains('cmd/tools/git_pre_commit_hook.vsh')
126+
// Git hook = shell script on OpenBSD
127+
$if openbsd {
128+
assert res.output.contains('git_pre_commit_hook.sh')
129+
} $else {
130+
assert res.output.contains('cmd/tools/git_pre_commit_hook.vsh')
131+
}
112132
assert res.output.contains(hook_file)
113133
assert res.output.contains('> Both files are exactly the same.')
114134
assert !res.output.contains('> Use `v git-fmt-hook install`')
@@ -124,7 +144,6 @@ fn test_run_git_fmt_hook_install() {
124144
assert dres.output.contains("+\tprintln('hi')")
125145
second := os.execute_or_exit('${os.quoted_path(vexe)} git-fmt-hook install')
126146
assert second.exit_code == 0
127-
assert second.output.contains('> Done.'), 'second:\n${second}'
128147
}
129148

130149
fn test_run_git_fmt_hook_remove() {

0 commit comments

Comments
 (0)