Skip to content

Commit 738b784

Browse files
committed
improving logs files
1 parent b81f549 commit 738b784

File tree

1 file changed

+72
-31
lines changed

1 file changed

+72
-31
lines changed

bolt/util.py

+72-31
Original file line numberDiff line numberDiff line change
@@ -21,49 +21,90 @@ def get_project_root():
2121
project_root = dirpath.parent
2222
return project_root
2323

24-
2524
def execute_command(command, log_file_path=None):
2625
"""
27-
Executes a shell command.
26+
Executes a shell command, streaming output to console, logging, and capturing errors.
2827
2928
Parameters:
3029
- command: Command to be executed as a formatted string.
3130
- log_file_path: Optional path to a log file to capture the command output.
3231
33-
Note:
34-
- If no log_file_path is specified, the outputs will be printed in the terminal and predefined logfile .
35-
- If log_file_path is specified, the log will only be written to the specified file.
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.
3637
"""
3738
logger.info(command.strip())
3839

40+
# Open the log file if a path is specified
41+
log_file = None
3942
if log_file_path:
40-
with log_file_path.open('a') as log_file:
41-
process = subprocess.run(
42-
command,
43-
shell=True,
44-
executable='/bin/bash',
45-
check=True,
46-
stdout=log_file,
47-
stderr=subprocess.STDOUT,
48-
text=True,
49-
encoding='utf-8'
50-
)
51-
else:
52-
process = subprocess.run(
53-
command,
54-
shell=True,
55-
executable='/bin/bash',
56-
check=True,
57-
capture_output=True,
58-
text=True,
59-
encoding='utf-8'
60-
)
61-
if process.stdout:
62-
logger.info(process.stdout)
63-
if process.stderr:
64-
logger.error(process.stderr)
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)
105+
106+
return process
65107

66-
return(process)
67108

68109
def command_prepare(command):
69110
return f'set -o pipefail; {textwrap.dedent(command)}'

0 commit comments

Comments
 (0)