@@ -53,9 +53,9 @@ async def run_command(
53
53
"""Run a command asynchronously and return its process ID."""
54
54
55
55
command_obj = CommandManager (command , env , cwd )
56
- process = await command_obj .run ()
57
- self .commands [process . pid ] = command_obj
58
- return process . pid
56
+ pid = await command_obj .run ()
57
+ self .commands [pid ] = command_obj
58
+ return pid
59
59
60
60
def get (self , pid : int ) -> "CommandManager" :
61
61
"""Get the CommandManager object for a given process ID."""
@@ -98,7 +98,6 @@ async def __aexit__(self, exc_type, exc_value, traceback):
98
98
def handle_sigint (self , signum , frame ):
99
99
"""Handle the SIGINT signal."""
100
100
101
- print ("SIGINT received." )
102
101
asyncio .create_task (self .kill ())
103
102
104
103
async def wait (
@@ -121,38 +120,45 @@ async def wait(
121
120
command_string = " " .join (self .command )
122
121
await self .kill ()
123
122
print (
124
- "Timeout: The process: %s with command: '%s' didn't complete within %s seconds."
123
+ "Timeout: The process (PID %d; command: '%s') did not complete within %s seconds."
125
124
% (self .process .pid , command_string , timeout )
126
125
)
127
126
128
127
async def run (self ):
129
128
"""Run the subprocess, streaming the logs to temporary files"""
130
129
131
- self .temp_dir = tempfile .mkdtemp ()
132
- stdout_logfile = os .path .join (self .temp_dir , "stdout.log" )
133
- stderr_logfile = os .path .join (self .temp_dir , "stderr.log" )
134
-
135
- try :
136
- # returns when process has been started,
137
- # not when it is finished...
138
- self .process = await asyncio .create_subprocess_exec (
139
- * self .command ,
140
- cwd = self .cwd ,
141
- env = self .env ,
142
- stdout = open (stdout_logfile , "w" ),
143
- stderr = open (stderr_logfile , "w" ),
144
- )
130
+ if not self .run_called :
131
+ self .temp_dir = tempfile .mkdtemp ()
132
+ stdout_logfile = os .path .join (self .temp_dir , "stdout.log" )
133
+ stderr_logfile = os .path .join (self .temp_dir , "stderr.log" )
134
+
135
+ try :
136
+ # returns when process has been started,
137
+ # not when it is finished...
138
+ self .process = await asyncio .create_subprocess_exec (
139
+ * self .command ,
140
+ cwd = self .cwd ,
141
+ env = self .env ,
142
+ stdout = open (stdout_logfile , "w" ),
143
+ stderr = open (stderr_logfile , "w" ),
144
+ )
145
145
146
- self .log_files ["stdout" ] = stdout_logfile
147
- self .log_files ["stderr" ] = stderr_logfile
146
+ self .log_files ["stdout" ] = stdout_logfile
147
+ self .log_files ["stderr" ] = stderr_logfile
148
148
149
- self .run_called = True
150
- return self .process
151
- except Exception as e :
152
- print ("Error starting subprocess: %s" % e )
153
- self .cleanup ()
149
+ self .run_called = True
150
+ return self .process .pid
151
+ except Exception as e :
152
+ print ("Error starting subprocess: %s" % e )
153
+ self .cleanup ()
154
+ else :
155
+ command_string = " " .join (self .command )
156
+ print (
157
+ "Command '%s' has already been called. Please create another CommandManager object."
158
+ % command_string
159
+ )
154
160
155
- async def stream_logs (
161
+ async def stream_log (
156
162
self ,
157
163
stream : str ,
158
164
position : Optional [int ] = None ,
@@ -161,13 +167,13 @@ async def stream_logs(
161
167
):
162
168
"""Stream logs from the subprocess using the log files"""
163
169
164
- if self .run_called is False :
165
- raise ValueError ("No command run yet to get the logs for..." )
170
+ if not self .run_called :
171
+ raise RuntimeError ("No command run yet to get the logs for..." )
166
172
167
173
if stream not in self .log_files :
168
174
raise ValueError (
169
175
"No log file found for '%s', valid values are: %s"
170
- % (stream , list (self .log_files .keys ()))
176
+ % (stream , ", " . join (self .log_files .keys ()))
171
177
)
172
178
173
179
log_file = self .log_files [stream ]
@@ -206,18 +212,18 @@ async def stream_logs(
206
212
continue
207
213
208
214
position = f .tell ()
209
- yield position , line .strip ()
215
+ yield position , line .rstrip ()
210
216
211
217
async def emit_logs (self , stream : str = "stdout" , custom_logger : Callable = print ):
212
- """Helper function to iterate over stream_logs """
218
+ """Helper function to iterate over stream_log """
213
219
214
- async for _ , line in self .stream_logs (stream ):
220
+ async for _ , line in self .stream_log (stream ):
215
221
custom_logger (line )
216
222
217
223
def cleanup (self ):
218
224
"""Clean up log files for a running subprocesses."""
219
225
220
- if hasattr ( self , "temp_dir" ) :
226
+ if self . run_called :
221
227
shutil .rmtree (self .temp_dir , ignore_errors = True )
222
228
223
229
async def kill (self , termination_timeout : float = 5 ):
@@ -272,7 +278,7 @@ async def main():
272
278
273
279
# stream logs line by line and check for existence of a string, noting down the position
274
280
interesting_position = 0
275
- async for position , line in command_obj .stream_logs (stream = "stdout" ):
281
+ async for position , line in command_obj .stream_log (stream = "stdout" ):
276
282
print (line )
277
283
if "alpha is" in line :
278
284
interesting_position = position
@@ -290,21 +296,21 @@ async def main():
290
296
"resuming streaming from: %s while process is still running..."
291
297
% interesting_position
292
298
)
293
- async for position , line in command_obj .stream_logs (
299
+ async for position , line in command_obj .stream_log (
294
300
stream = "stdout" , position = interesting_position
295
301
):
296
302
print (line )
297
303
298
304
# this will be instantaneous since the process has finished and we just read from the log file
299
305
print ("process has ended by now... streaming again from scratch.." )
300
- async for position , line in command_obj .stream_logs (stream = "stdout" ):
306
+ async for position , line in command_obj .stream_log (stream = "stdout" ):
301
307
print (line )
302
308
303
309
# this will be instantaneous since the process has finished and we just read from the log file
304
310
print (
305
311
"process has ended by now... streaming again but from position of choice.."
306
312
)
307
- async for position , line in command_obj .stream_logs (
313
+ async for position , line in command_obj .stream_log (
308
314
stream = "stdout" , position = interesting_position
309
315
):
310
316
print (line )
0 commit comments