@@ -14,7 +14,7 @@ use metadata::PerfMetadata;
1414use perf_map:: ProcessSymbols ;
1515use shared:: Command as FifoCommand ;
1616use std:: collections:: HashSet ;
17- use std:: path:: PathBuf ;
17+ use std:: path:: { Path , PathBuf } ;
1818use std:: process:: Command ;
1919use std:: time:: Duration ;
2020use std:: { cell:: OnceCell , collections:: HashMap , process:: ExitStatus } ;
@@ -33,6 +33,55 @@ pub mod unwind_data;
3333
3434const PERF_DATA_PREFIX : & str = "perf.data." ;
3535
36+ struct EnvGuard {
37+ post_bench_script : PathBuf ,
38+ }
39+
40+ impl EnvGuard {
41+ fn execute_script_from_path < P : AsRef < Path > > ( path : P ) -> anyhow:: Result < ( ) > {
42+ let path = path. as_ref ( ) ;
43+ if !path. exists ( ) || !path. is_file ( ) {
44+ warn ! ( "Script not found or not a file: {}" , path. display( ) ) ;
45+ return Ok ( ( ) ) ;
46+ }
47+
48+ let output = Command :: new ( "bash" ) . args ( [ & path] ) . output ( ) ?;
49+ if !output. status . success ( ) {
50+ info ! ( "stdout: {}" , String :: from_utf8_lossy( & output. stdout) ) ;
51+ error ! ( "stderr: {}" , String :: from_utf8_lossy( & output. stderr) ) ;
52+ bail ! ( "Failed to execute script: {}" , path. display( ) ) ;
53+ }
54+
55+ Ok ( ( ) )
56+ }
57+
58+ pub fn setup_with_scripts < P : AsRef < Path > > ( pre_bench_script : P , post_bench_script : P ) -> Self {
59+ if let Err ( e) = Self :: execute_script_from_path ( pre_bench_script. as_ref ( ) ) {
60+ warn ! ( "Failed to execute pre-bench script: {}" , e) ;
61+ println ! ( "asdf: {e}" ) ;
62+ }
63+
64+ Self {
65+ post_bench_script : post_bench_script. as_ref ( ) . to_path_buf ( ) ,
66+ }
67+ }
68+
69+ pub fn setup ( ) -> Self {
70+ Self :: setup_with_scripts (
71+ "/usr/local/bin/codspeed-pre-bench" ,
72+ "/usr/local/bin/codspeed-post-bench" ,
73+ )
74+ }
75+ }
76+
77+ impl Drop for EnvGuard {
78+ fn drop ( & mut self ) {
79+ if let Err ( e) = Self :: execute_script_from_path ( & self . post_bench_script ) {
80+ warn ! ( "Failed to execute post-bench script: {}" , e) ;
81+ }
82+ }
83+ }
84+
3685pub struct PerfRunner {
3786 perf_dir : TempDir ,
3887 benchmark_data : OnceCell < BenchmarkData > ,
@@ -139,7 +188,11 @@ impl PerfRunner {
139188
140189 Ok ( ( ) )
141190 } ;
142- run_command_with_log_pipe_and_callback ( cmd, on_process_started) . await
191+
192+ {
193+ let _guard = EnvGuard :: setup ( ) ;
194+ run_command_with_log_pipe_and_callback ( cmd, on_process_started) . await
195+ }
143196 }
144197
145198 pub async fn save_files_to ( & self , profile_folder : & PathBuf ) -> anyhow:: Result < ( ) > {
@@ -402,3 +455,49 @@ impl BenchmarkData {
402455 self . bench_order_by_pid . values ( ) . map ( |v| v. len ( ) ) . sum ( )
403456 }
404457}
458+ #[ cfg( test) ]
459+ mod tests {
460+ use tempfile:: NamedTempFile ;
461+
462+ use super :: * ;
463+ use std:: {
464+ io:: { Read , Write } ,
465+ os:: unix:: fs:: PermissionsExt ,
466+ } ;
467+
468+ #[ test]
469+ fn test_env_guard_no_crash ( ) {
470+ fn create_run_script ( content : & str ) -> anyhow:: Result < NamedTempFile > {
471+ let rwx = std:: fs:: Permissions :: from_mode ( 0o777 ) ;
472+ let mut script_file = tempfile:: Builder :: new ( )
473+ . suffix ( ".sh" )
474+ . permissions ( rwx)
475+ . keep ( true )
476+ . tempfile ( ) ?;
477+ script_file. write_all ( content. as_bytes ( ) ) ?;
478+
479+ Ok ( script_file)
480+ }
481+
482+ let mut tmp_dst = tempfile:: NamedTempFile :: new ( ) . unwrap ( ) ;
483+
484+ let pre_script = create_run_script ( & format ! (
485+ "#!/usr/bin/env bash\n echo \" pre\" >> {}" ,
486+ tmp_dst. path( ) . display( )
487+ ) )
488+ . unwrap ( ) ;
489+ let post_script = create_run_script ( & format ! (
490+ "#!/usr/bin/env bash\n echo \" post\" >> {}" ,
491+ tmp_dst. path( ) . display( )
492+ ) )
493+ . unwrap ( ) ;
494+
495+ {
496+ let _guard = EnvGuard :: setup_with_scripts ( pre_script. path ( ) , post_script. path ( ) ) ;
497+ }
498+
499+ let mut result = String :: new ( ) ;
500+ tmp_dst. read_to_string ( & mut result) . unwrap ( ) ;
501+ assert_eq ! ( result, "pre\n post\n " ) ;
502+ }
503+ }
0 commit comments