@@ -11,9 +11,58 @@ use crate::run::{check_system::SystemInfo, config::Config};
1111use async_trait:: async_trait;
1212use std:: fs:: canonicalize;
1313use std:: io:: Write ;
14+ use std:: path:: { Path , PathBuf } ;
1415use std:: process:: Command ;
1516use tempfile:: NamedTempFile ;
1617
18+ struct HookScriptsGuard {
19+ post_bench_script : PathBuf ,
20+ }
21+
22+ impl HookScriptsGuard {
23+ fn execute_script_from_path < P : AsRef < Path > > ( path : P ) -> anyhow:: Result < ( ) > {
24+ let path = path. as_ref ( ) ;
25+ if !path. exists ( ) || !path. is_file ( ) {
26+ debug ! ( "Script not found or not a file: {}" , path. display( ) ) ;
27+ return Ok ( ( ) ) ;
28+ }
29+
30+ let output = Command :: new ( "bash" ) . args ( [ & path] ) . output ( ) ?;
31+ if !output. status . success ( ) {
32+ debug ! ( "stdout: {}" , String :: from_utf8_lossy( & output. stdout) ) ;
33+ debug ! ( "stderr: {}" , String :: from_utf8_lossy( & output. stderr) ) ;
34+ bail ! ( "Failed to execute script: {}" , path. display( ) ) ;
35+ }
36+
37+ Ok ( ( ) )
38+ }
39+
40+ pub fn setup_with_scripts < P : AsRef < Path > > ( pre_bench_script : P , post_bench_script : P ) -> Self {
41+ if let Err ( e) = Self :: execute_script_from_path ( pre_bench_script. as_ref ( ) ) {
42+ debug ! ( "Failed to execute pre-bench script: {e}" ) ;
43+ }
44+
45+ Self {
46+ post_bench_script : post_bench_script. as_ref ( ) . to_path_buf ( ) ,
47+ }
48+ }
49+
50+ pub fn setup ( ) -> Self {
51+ Self :: setup_with_scripts (
52+ "/usr/local/bin/codspeed-pre-bench" ,
53+ "/usr/local/bin/codspeed-post-bench" ,
54+ )
55+ }
56+ }
57+
58+ impl Drop for HookScriptsGuard {
59+ fn drop ( & mut self ) {
60+ if let Err ( e) = Self :: execute_script_from_path ( & self . post_bench_script ) {
61+ debug ! ( "Failed to execute post-bench script: {e}" ) ;
62+ }
63+ }
64+ }
65+
1766pub struct WallTimeExecutor {
1867 perf : Option < PerfRunner > ,
1968}
@@ -86,17 +135,20 @@ impl Executor for WallTimeExecutor {
86135 cmd. current_dir ( abs_cwd) ;
87136 }
88137
89- let ( _env_file, bench_cmd) = Self :: walltime_bench_cmd ( config, run_data) ?;
138+ let status = {
139+ let _guard = HookScriptsGuard :: setup ( ) ;
90140
91- let status = if let Some ( perf) = & self . perf
92- && config. enable_perf
93- {
94- perf. run ( cmd, & bench_cmd, config) . await
95- } else {
96- cmd. args ( [ "sh" , "-c" , & bench_cmd] ) ;
97- debug ! ( "cmd: {cmd:?}" ) ;
141+ let ( _env_file, bench_cmd) = Self :: walltime_bench_cmd ( config, run_data) ?;
142+ if let Some ( perf) = & self . perf
143+ && config. enable_perf
144+ {
145+ perf. run ( cmd, & bench_cmd, config) . await
146+ } else {
147+ cmd. args ( [ "sh" , "-c" , & bench_cmd] ) ;
148+ debug ! ( "cmd: {cmd:?}" ) ;
98149
99- run_command_with_log_pipe ( cmd) . await
150+ run_command_with_log_pipe ( cmd) . await
151+ }
100152 } ;
101153
102154 let status =
@@ -127,3 +179,51 @@ impl Executor for WallTimeExecutor {
127179 Ok ( ( ) )
128180 }
129181}
182+
183+ #[ cfg( test) ]
184+ mod tests {
185+ use tempfile:: NamedTempFile ;
186+
187+ use super :: * ;
188+ use std:: {
189+ io:: { Read , Write } ,
190+ os:: unix:: fs:: PermissionsExt ,
191+ } ;
192+
193+ #[ test]
194+ fn test_env_guard_no_crash ( ) {
195+ fn create_run_script ( content : & str ) -> anyhow:: Result < NamedTempFile > {
196+ let rwx = std:: fs:: Permissions :: from_mode ( 0o777 ) ;
197+ let mut script_file = tempfile:: Builder :: new ( )
198+ . suffix ( ".sh" )
199+ . permissions ( rwx)
200+ . keep ( true )
201+ . tempfile ( ) ?;
202+ script_file. write_all ( content. as_bytes ( ) ) ?;
203+
204+ Ok ( script_file)
205+ }
206+
207+ let mut tmp_dst = tempfile:: NamedTempFile :: new ( ) . unwrap ( ) ;
208+
209+ let pre_script = create_run_script ( & format ! (
210+ "#!/usr/bin/env bash\n echo \" pre\" >> {}" ,
211+ tmp_dst. path( ) . display( )
212+ ) )
213+ . unwrap ( ) ;
214+ let post_script = create_run_script ( & format ! (
215+ "#!/usr/bin/env bash\n echo \" post\" >> {}" ,
216+ tmp_dst. path( ) . display( )
217+ ) )
218+ . unwrap ( ) ;
219+
220+ {
221+ let _guard =
222+ HookScriptsGuard :: setup_with_scripts ( pre_script. path ( ) , post_script. path ( ) ) ;
223+ }
224+
225+ let mut result = String :: new ( ) ;
226+ tmp_dst. read_to_string ( & mut result) . unwrap ( ) ;
227+ assert_eq ! ( result, "pre\n post\n " ) ;
228+ }
229+ }
0 commit comments