@@ -12,9 +12,25 @@ pub struct CommandLine {
1212 pub temp_env_file : Option < tempfile:: NamedTempFile > ,
1313}
1414
15+ impl Clone for CommandLine {
16+ fn clone ( & self ) -> Self {
17+ Self {
18+ sudo : self . sudo ,
19+ app : self . app . clone ( ) ,
20+ app_in_path : self . app_in_path ,
21+ args : self . args . clone ( ) ,
22+ env : self . env . clone ( ) ,
23+ temp_env_file : None , // Don't clone the temp file, create a new one if needed
24+ }
25+ }
26+ }
27+
1528impl CommandLine {
1629 pub fn from_vec ( vec : & Vec < String > ) -> anyhow:: Result < Self > {
30+ log:: debug!( "Creating CommandLine from vector: {:?}" , vec) ;
31+
1732 if vec. is_empty ( ) {
33+ log:: error!( "Empty command line vector provided" ) ;
1834 return Err ( anyhow:: anyhow!( "empty command line" ) ) ;
1935 }
2036
@@ -23,29 +39,39 @@ impl CommandLine {
2339 let mut args = Vec :: new ( ) ;
2440
2541 for arg in vec {
42+ log:: trace!( "Processing argument: {}" , arg) ;
2643 if arg == "sudo" {
44+ log:: debug!( "Sudo flag detected" ) ;
2745 sudo = true ;
2846 } else if app. is_empty ( ) {
47+ log:: debug!( "Setting application name: {}" , arg) ;
2948 app = arg. to_string ( ) ;
3049 } else {
50+ log:: trace!( "Adding argument: {}" , arg) ;
3151 args. push ( arg. to_string ( ) ) ;
3252 }
3353 }
3454
3555 if app. is_empty ( ) {
56+ log:: error!( "Could not determine application name from: {:?}" , vec) ;
3657 return Err ( anyhow:: anyhow!(
3758 "could not determine application name from command line: {:?}" ,
3859 vec
3960 ) ) ;
4061 }
4162
4263 let app_in_path = if let Ok ( path) = which:: which ( & app) {
64+ log:: debug!( "Found application in path: {}" , path. display( ) ) ;
4365 app = path. to_string_lossy ( ) . to_string ( ) ;
4466 true
4567 } else {
68+ log:: debug!( "Application '{}' not found in PATH" , app) ;
4669 false
4770 } ;
4871
72+ log:: debug!( "Created CommandLine: sudo={}, app={}, app_in_path={}, args={:?}" ,
73+ sudo, app, app_in_path, args) ;
74+
4975 Ok ( Self {
5076 sudo,
5177 app,
@@ -60,39 +86,82 @@ impl CommandLine {
6086 vec : & Vec < String > ,
6187 env : BTreeMap < String , String > ,
6288 ) -> anyhow:: Result < Self > {
89+ log:: debug!( "Creating CommandLine with environment variables" ) ;
90+ log:: trace!( "Environment variables: {:?}" , env) ;
6391 let mut cmd = Self :: from_vec ( vec) ?;
6492 cmd. env = env;
6593 Ok ( cmd)
6694 }
6795
96+ fn interpolate_variables ( & mut self ) -> anyhow:: Result < ( ) > {
97+ log:: debug!( "Interpolating variables from environment: {:?}" , self . env) ;
98+
99+ self . args = self . args . iter ( ) . map ( |arg| {
100+ let mut result = arg. clone ( ) ;
101+ for ( key, value) in & self . env {
102+ let pattern = format ! ( "${{{}}}" , key) ;
103+ if result. contains ( & pattern) {
104+ log:: debug!( "Replacing {} with {}" , pattern, value) ;
105+ result = result. replace ( & pattern, value) ;
106+ }
107+ }
108+ result
109+ } ) . collect ( ) ;
110+
111+ log:: debug!( "After interpolation: {:?}" , self . args) ;
112+ Ok ( ( ) )
113+ }
114+
68115 pub async fn execute ( & self ) -> anyhow:: Result < String > {
69- let output = tokio:: process:: Command :: new ( & self . app )
70- . args ( & self . args )
71- . output ( )
72- . await ?;
116+ log:: info!( "Executing command: {}" , self ) ;
117+ log:: debug!( "Full command details: {:?}" , self ) ;
118+
119+ // Create a mutable copy for interpolation
120+ let mut cmd = self . clone ( ) ;
121+ cmd. interpolate_variables ( ) ?;
122+
123+ let mut command = tokio:: process:: Command :: new ( & cmd. app ) ;
124+ command. args ( & cmd. args ) ;
125+
126+ // Log environment variables if present
127+ if !cmd. env . is_empty ( ) {
128+ log:: debug!( "Setting environment variables: {:?}" , cmd. env) ;
129+ command. envs ( & cmd. env ) ;
130+ }
131+
132+ let output = command. output ( ) . await ?;
133+ log:: debug!( "Command completed with status: {:?}" , output. status) ;
73134
74135 let mut parts = vec ! [ ] ;
75136
76137 let stdout = String :: from_utf8_lossy ( & output. stdout ) ;
77138 let stderr = String :: from_utf8_lossy ( & output. stderr ) ;
78139
79140 if !output. status . success ( ) {
141+ log:: warn!( "Command failed with exit code: {}" , output. status) ;
80142 parts. push ( format ! ( "EXIT CODE: {}" , & output. status) ) ;
81143 }
82144
83145 if !stdout. is_empty ( ) {
146+ log:: trace!( "Command stdout: {}" , stdout) ;
84147 parts. push ( stdout. to_string ( ) ) ;
85148 }
86149
87150 if !stderr. is_empty ( ) {
88151 if output. status . success ( ) {
152+ log:: debug!( "Command stderr (success): {}" , stderr) ;
89153 parts. push ( stderr. to_string ( ) ) ;
90154 } else {
155+ log:: error!( "Command stderr (failure): {}" , stderr) ;
91156 parts. push ( format ! ( "ERROR: {}" , stderr) ) ;
92157 }
93158 }
94159
95- Ok ( parts. join ( "\n " ) )
160+ let result = parts. join ( "\n " ) ;
161+ log:: debug!( "Command execution completed, output length: {}" , result. len( ) ) ;
162+ log:: trace!( "Command output: {}" , result) ;
163+
164+ Ok ( result)
96165 }
97166}
98167
0 commit comments