@@ -31,6 +31,52 @@ pub mod unwind_data;
3131
3232const PERF_DATA_PREFIX : & str = "perf.data." ;
3333
34+ struct EnvGuard ;
35+
36+ impl EnvGuard {
37+ fn execute_script_from_env ( script_env_var : & str ) -> anyhow:: Result < ( ) > {
38+ let Ok ( script_path) = std:: env:: var ( script_env_var) else {
39+ debug ! ( "Couldn't find {script_env_var}, skipping script execution" ) ;
40+ return Ok ( ( ) ) ;
41+ } ;
42+
43+ if script_path. is_empty ( ) {
44+ return Ok ( ( ) ) ;
45+ }
46+
47+ let path = std:: path:: Path :: new ( & script_path) ;
48+ if !path. exists ( ) || !path. is_file ( ) {
49+ warn ! ( "Script not found or not a file: {}" , script_path) ;
50+ return Ok ( ( ) ) ;
51+ }
52+
53+ let output = Command :: new ( "bash" ) . args ( [ & script_path] ) . output ( ) ?;
54+ if !output. status . success ( ) {
55+ info ! ( "stdout: {}" , String :: from_utf8_lossy( & output. stdout) ) ;
56+ error ! ( "stderr: {}" , String :: from_utf8_lossy( & output. stderr) ) ;
57+ bail ! ( "Failed to execute script: {}" , script_path) ;
58+ }
59+
60+ Ok ( ( ) )
61+ }
62+
63+ pub fn setup ( ) -> Self {
64+ if let Err ( e) = Self :: execute_script_from_env ( "CODSPEED_PRE_STARTUP_SCRIPT" ) {
65+ warn ! ( "Failed to execute pre-startup script: {}" , e) ;
66+ println ! ( "asdf: {e}" ) ;
67+ }
68+ Self
69+ }
70+ }
71+
72+ impl Drop for EnvGuard {
73+ fn drop ( & mut self ) {
74+ if let Err ( e) = Self :: execute_script_from_env ( "CODSPEED_POST_CLEANUP_SCRIPT" ) {
75+ warn ! ( "Failed to execute post-cleanup script: {}" , e) ;
76+ }
77+ }
78+ }
79+
3480pub struct PerfRunner {
3581 perf_dir : TempDir ,
3682 benchmark_data : OnceCell < BenchmarkData > ,
@@ -126,7 +172,11 @@ impl PerfRunner {
126172
127173 Ok ( ( ) )
128174 } ;
129- run_command_with_log_pipe_and_callback ( cmd, on_process_started) . await
175+
176+ {
177+ let _guard = EnvGuard :: setup ( ) ;
178+ run_command_with_log_pipe_and_callback ( cmd, on_process_started) . await
179+ }
130180 }
131181
132182 pub async fn save_files_to ( & self , profile_folder : & PathBuf ) -> anyhow:: Result < ( ) > {
@@ -389,3 +439,82 @@ impl BenchmarkData {
389439 self . bench_order_by_pid . values ( ) . map ( |v| v. len ( ) ) . sum ( )
390440 }
391441}
442+ #[ cfg( test) ]
443+ mod tests {
444+ use tempfile:: NamedTempFile ;
445+
446+ use super :: * ;
447+ use std:: {
448+ io:: { Read , Write } ,
449+ os:: unix:: fs:: PermissionsExt ,
450+ } ;
451+
452+ fn with_env < F > ( vars : & [ ( & str , & str ) ] , mut f : F )
453+ where
454+ F : FnMut ( ) ,
455+ {
456+ let original_vars: Vec < ( & str , std:: result:: Result < String , std:: env:: VarError > ) > =
457+ vars. iter ( ) . map ( |( k, _) | ( * k, std:: env:: var ( * k) ) ) . collect ( ) ;
458+
459+ for ( k, v) in vars {
460+ std:: env:: set_var ( k, v) ;
461+ }
462+
463+ f ( ) ;
464+
465+ for ( k, v) in original_vars {
466+ if let Ok ( val) = v {
467+ std:: env:: set_var ( k, val) ;
468+ } else {
469+ std:: env:: remove_var ( k) ;
470+ }
471+ }
472+ }
473+
474+ #[ test]
475+ fn test_env_guard_no_crash ( ) {
476+ fn create_run_script ( content : & str ) -> anyhow:: Result < NamedTempFile > {
477+ let rwx = std:: fs:: Permissions :: from_mode ( 0o777 ) ;
478+ let mut script_file = tempfile:: Builder :: new ( )
479+ . suffix ( ".sh" )
480+ . permissions ( rwx)
481+ . keep ( true )
482+ . tempfile ( ) ?;
483+ script_file. write_all ( content. as_bytes ( ) ) ?;
484+
485+ Ok ( script_file)
486+ }
487+
488+ let mut tmp_dst = tempfile:: NamedTempFile :: new ( ) . unwrap ( ) ;
489+
490+ let pre_script = create_run_script ( & format ! (
491+ "#!/usr/bin/env bash\n echo \" pre\" >> {}" ,
492+ tmp_dst. path( ) . display( )
493+ ) )
494+ . unwrap ( ) ;
495+ let post_script = create_run_script ( & format ! (
496+ "#!/usr/bin/env bash\n echo \" post\" >> {}" ,
497+ tmp_dst. path( ) . display( )
498+ ) )
499+ . unwrap ( ) ;
500+
501+ let env_vars = [
502+ (
503+ "CODSPEED_PRE_STARTUP_SCRIPT" ,
504+ & * pre_script. path ( ) . to_string_lossy ( ) ,
505+ ) ,
506+ (
507+ "CODSPEED_POST_CLEANUP_SCRIPT" ,
508+ & post_script. path ( ) . to_string_lossy ( ) ,
509+ ) ,
510+ ] ;
511+
512+ with_env ( & env_vars, || {
513+ let _guard = EnvGuard :: setup ( ) ;
514+ } ) ;
515+
516+ let mut result = String :: new ( ) ;
517+ tmp_dst. read_to_string ( & mut result) . unwrap ( ) ;
518+ assert_eq ! ( result, "pre\n post\n " ) ;
519+ }
520+ }
0 commit comments