11import shlex
2+ import time
23from typing import Optional
34
45from ..core .interfaces import EnvironmentExecutor
@@ -48,8 +49,11 @@ def execute_command(self, command: str, working_dir: Optional[str] = None) -> tu
4849 Returns actual command exit code on success, or 1 for execution environment failures.
4950 """
5051 if self .debug :
52+ start_time = time .perf_counter ()
5153 workdir_info = f" (workdir: { working_dir } )" if working_dir else ""
5254 print (f"Executing docker command: sh -c '{ command } '{ workdir_info } " )
55+ else :
56+ start_time = None
5357
5458 try :
5559 # First, try with sh
@@ -59,22 +63,34 @@ def execute_command(self, command: str, working_dir: Optional[str] = None) -> tu
5963 stdout = result .output .decode ("utf-8" ) if result .output else ""
6064 stderr = ""
6165
62- if self .debug :
63- print (f"Docker command exit code: { result .exit_code } " )
66+ if self .debug and start_time is not None :
67+ elapsed_time = time .perf_counter () - start_time
68+ print (f"Docker command completed in { elapsed_time :.3f} s with exit code: { result .exit_code } " )
6469
6570 return stdout , stderr , result .exit_code
6671
6772 except docker .errors .APIError as e :
6873 # Check if this is a "sh not found" error
6974 if "executable file not found" in str (e ).lower () and "sh" in str (e ).lower ():
70- return self ._execute_command_direct (command , working_dir )
75+ return self ._execute_command_direct (command , working_dir , start_time )
7176 else :
77+ if self .debug and start_time is not None :
78+ elapsed_time = time .perf_counter () - start_time
79+ print (f"Docker command failed after { elapsed_time :.3f} s: { str (e )} " )
7280 return "" , f"Docker API error: { str (e )} " , 1
7381 except (OSError , ValueError ) as e :
82+ if self .debug and start_time is not None :
83+ elapsed_time = time .perf_counter () - start_time
84+ print (f"Docker command failed after { elapsed_time :.3f} s: { str (e )} " )
7485 return "" , f"Command execution failed: { str (e )} " , 1
7586
76- def _execute_command_direct (self , command : str , working_dir : Optional [str ] = None ) -> tuple [str , str , int ]:
87+ def _execute_command_direct (
88+ self , command : str , working_dir : Optional [str ] = None , start_time : Optional [float ] = None
89+ ) -> tuple [str , str , int ]:
7790 """Fallback: execute simple commands directly without shell."""
91+ if start_time is None :
92+ start_time = time .perf_counter ()
93+
7894 if self .debug :
7995 workdir_info = f" (workdir: { working_dir } )" if working_dir else ""
8096 print (f"Fallback: executing docker command directly: { command } { workdir_info } " )
@@ -83,6 +99,9 @@ def _execute_command_direct(self, command: str, working_dir: Optional[str] = Non
8399 # Handle only the simple cases we actually use
84100 cmd_parts = DockerExecutor ._parse_simple_command (command )
85101 if not cmd_parts :
102+ if self .debug :
103+ elapsed_time = time .perf_counter () - start_time
104+ print (f"Direct execution failed after { elapsed_time :.3f} s: command too complex" )
86105 return "" , f"Command too complex for direct execution (no shell available): { command } " , 1
87106
88107 if self .debug :
@@ -93,11 +112,15 @@ def _execute_command_direct(self, command: str, working_dir: Optional[str] = Non
93112 stderr = ""
94113
95114 if self .debug :
96- print (f"Direct execution exit code: { result .exit_code } " )
115+ elapsed_time = time .perf_counter () - start_time
116+ print (f"Direct execution completed in { elapsed_time :.3f} s with exit code: { result .exit_code } " )
97117
98118 return stdout , stderr , result .exit_code
99119
100120 except docker .errors .APIError as e :
121+ if self .debug :
122+ elapsed_time = time .perf_counter () - start_time
123+ print (f"Direct execution failed after { elapsed_time :.3f} s: { str (e )} " )
101124 return "" , f"Direct execution failed: { str (e )} " , 1
102125
103126 @staticmethod
0 commit comments