@@ -22,90 +22,28 @@ def get_project_root():
22
22
return project_root
23
23
24
24
def execute_command (command , log_file_path = None ):
25
- """
26
- Executes a shell command, streaming output to console, logging, and capturing errors.
27
-
28
- Parameters:
29
- - command: Command to be executed as a formatted string.
30
- - log_file_path: Optional path to a log file to capture the command output.
31
-
32
- Returns:
33
- - (stdout, stderr): A tuple containing the complete stdout and stderr of the command.
34
-
35
- Raises:
36
- - subprocess.CalledProcessError if the command exits with a non-zero status.
37
- """
38
- logger .info (command .strip ())
39
-
40
- # Open the log file if a path is specified
41
- log_file = None
42
- if log_file_path :
43
- log_file = log_file_path .open ('a' , encoding = 'utf-8' )
44
-
45
- # Start the process
46
- with subprocess .Popen (command , shell = True , executable = '/bin/bash' ,
47
- stdout = subprocess .PIPE , stderr = subprocess .PIPE ,
48
- text = True , encoding = 'utf-8' ) as process :
49
-
50
- # To collect the complete stdout and stderr
51
- full_stdout = []
52
- full_stderr = []
53
-
54
- # Stream stdout and stderr in real-time
55
- while True :
56
- stdout_line = process .stdout .readline ()
57
- stderr_line = process .stderr .readline ()
58
-
59
- # Handle stdout
60
- if stdout_line :
61
- full_stdout .append (stdout_line )
62
- if log_file :
63
- log_file .write (stdout_line )
64
- log_file .flush () # Ensure immediate write
65
- logger .info (stdout_line .strip ())
66
-
67
- # Handle stderr
68
- if stderr_line :
69
- full_stderr .append (stderr_line )
70
- if log_file :
71
- log_file .write (stderr_line )
72
- log_file .flush ()
73
- logger .error (stderr_line .strip ())
74
-
75
- # If the process has finished and there are no more lines, break
76
- if process .poll () is not None and not stdout_line and not stderr_line :
77
- break
78
-
79
- # Communicate to ensure we capture everything left in the buffers
80
- remaining_stdout , remaining_stderr = process .communicate ()
81
-
82
- # Handle remaining stdout
83
- if remaining_stdout :
84
- full_stdout .append (remaining_stdout )
85
- if log_file :
86
- log_file .write (remaining_stdout )
87
- log_file .flush ()
88
- logger .info (remaining_stdout .strip ())
89
-
90
- # Handle remaining stderr
91
- if remaining_stderr :
92
- full_stderr .append (remaining_stderr )
93
- if log_file :
94
- log_file .write (remaining_stderr )
95
- log_file .flush ()
96
- logger .error (remaining_stderr .strip ())
97
-
98
- # Close the log file if it was opened
99
- if log_file :
100
- log_file .close ()
101
-
102
- # Combine all the lines into final stdout and stderr strings
103
- stdout_str = '' .join (full_stdout )
104
- stderr_str = '' .join (full_stderr )
25
+ logger .info ("Executing command: %s" , command )
26
+ # Open the process with stderr merged to stdout
27
+ process = subprocess .Popen (
28
+ command ,
29
+ shell = True ,
30
+ executable = '/bin/bash' ,
31
+ stdout = subprocess .PIPE ,
32
+ stderr = subprocess .STDOUT ,
33
+ text = True ,
34
+ bufsize = 1 # Line-buffered output
35
+ )
105
36
37
+ # Capture output in real time
38
+ with process .stdout :
39
+ for line in iter (process .stdout .readline , '' ):
40
+ logger .info (line .strip ())
41
+ if log_file_path :
42
+ with open (log_file_path , 'a' , encoding = 'utf-8' ) as log_file :
43
+ log_file .write (line )
44
+ process .wait ()
106
45
return process
107
46
108
-
109
47
def command_prepare (command ):
110
48
return f'set -o pipefail; { textwrap .dedent (command )} '
111
49
0 commit comments