3
3
import subprocess
4
4
import threading
5
5
import random
6
+ import queue
6
7
7
8
_windows_env = None
8
9
10
+
9
11
def setup_windows_build ():
10
12
11
13
global _windows_env
@@ -242,26 +244,25 @@ def _busy_spinner(evnt):
242
244
wait = random .randint (10 , 100 ) * 0.001
243
245
244
246
245
- def spawn (cmd_ , out_to_screen = True , spinner = False , env = None , cmpl = False ):
246
- if env is None :
247
- env = os .environ
247
+ def _convert_line (lne ):
248
+ try :
249
+ lne = lne .decode ('utf-8' )
250
+ except UnicodeDecodeError :
251
+ for char in lne :
252
+ if 32 <= char <= 125 or char in (b'\r ' , b'\n ' ):
253
+ continue
248
254
249
- if isinstance ( cmd_ [ 0 ], str ):
250
- cmd_ = [ cmd_ [:]]
255
+ lne = lne . replace ( char , b'' )
256
+ lne = lne . decode ( 'utf-8' )
251
257
252
- cmd_ = ' && ' . join ( ' ' . join ( c ) for c in cmd_ )
258
+ return lne
253
259
254
- p = subprocess .Popen (
255
- cmd_ ,
256
- stdout = subprocess .PIPE ,
257
- stderr = subprocess .PIPE ,
258
- shell = True ,
259
- env = env
260
- )
261
260
262
- if not sys .platform .startswith ('win' ):
263
- os .set_blocking (p .stdout .fileno (), False )
264
- os .set_blocking (p .stderr .fileno (), False )
261
+ def process_output (myproc , out_to_screen , spinner , cmpl , out_queue ): #output-consuming thread
262
+ line = b''
263
+ err_line = b''
264
+
265
+ last_line_len = - 1
265
266
266
267
event = threading .Event ()
267
268
@@ -272,36 +273,23 @@ def spawn(cmd_, out_to_screen=True, spinner=False, env=None, cmpl=False):
272
273
else :
273
274
t = None
274
275
275
- output_buffer = []
276
- last_line_len = - 1
276
+ while True :
277
+ if myproc .poll () is not None :
278
+ break
277
279
278
- def _convert_line (lne ):
279
- try :
280
- lne = lne .decode ('utf-8' )
281
- except UnicodeDecodeError :
282
- for char in lne :
283
- if 32 <= char <= 125 or char in (b'\r ' , b'\n ' ):
284
- continue
285
-
286
- lne = lne .replace (char , b'' )
287
- lne = lne .decode ('utf-8' )
288
-
289
- return lne
290
-
291
- try :
292
- while p .poll () is None :
293
- line = p .stdout .readline ()
294
- if line is not None and line .strip ():
280
+ # --- extract line using read(1)
281
+ out = myproc .stdout .read (1 )
282
+ while out :
283
+ line += out
284
+ if out == b'\n ' :
295
285
line = _convert_line (line .strip ())
296
- output_buffer . append (line )
286
+ out_queue . put (line )
297
287
298
288
if not spinner and out_to_screen :
299
- if (
300
- cmpl and
301
- (line .startswith ('[' ) or line .startswith ('--' )) and
302
- last_line_len != - 1
303
- ):
304
- sys .stdout .write ('\r ' )
289
+ if cmpl and (line .startswith ('[' ) or line .startswith ('--' )):
290
+ if last_line_len != - 1 :
291
+ sys .stdout .write ('\r ' )
292
+
305
293
if len (line ) < last_line_len :
306
294
padding = ' ' * (last_line_len - len (line ))
307
295
else :
@@ -315,57 +303,101 @@ def _convert_line(lne):
315
303
316
304
sys .stdout .flush ()
317
305
318
- line = p .stderr .readline ()
319
- while line is not None and line .strip ():
320
- if not spinner and out_to_screen and cmpl and last_line_len != - 1 :
321
- sys .stdout .write ('\n ' )
322
- sys .stdout .flush ()
323
- last_line_len = - 1
306
+ line = b''
324
307
325
- line = _convert_line (line .strip ())
326
- output_buffer .append (line )
308
+ out = myproc .stdout .read (1 )
309
+
310
+ out = myproc .stderr .read (1 )
327
311
312
+ while out :
313
+ if not spinner and out_to_screen and cmpl and last_line_len != - 1 :
314
+ sys .stdout .write ('\n ' )
315
+ sys .stdout .flush ()
316
+ last_line_len = - 1
317
+
318
+ err_line += out
319
+ if out == b'\n ' :
320
+ err_line = _convert_line (err_line .strip ())
321
+ out_queue .put (err_line )
328
322
if out_to_screen and not spinner :
329
- sys .stderr .write (line + '\n ' )
323
+ sys .stderr .write (err_line + '\n ' )
330
324
sys .stderr .flush ()
331
325
332
- line = p .stderr .readline ( )
326
+ out = myproc .stderr .read ( 1 )
333
327
334
- except KeyboardInterrupt :
335
- if t is not None :
336
- event .set ()
337
- t .join ()
328
+ if t is not None :
329
+ event .set ()
330
+ t .join ()
338
331
339
- print ()
340
- print (output_buffer )
332
+ sys .stdout .write ('\n ' )
333
+ sys .stdout .flush ()
334
+
335
+ elif out_to_screen and cmpl and last_line_len != - 1 :
336
+ sys .stdout .write ('\n ' )
337
+ sys .stdout .flush ()
341
338
342
- if not p .stdout .closed :
343
- p .stdout .close ()
344
339
345
- if not p .stderr .closed :
346
- p .stderr .close ()
340
+ myprocess = subprocess .Popen ('myprogram.exe' , stdout = subprocess .PIPE ) #output-producing process
347
341
348
- raise
342
+
343
+ def spawn (cmd_ , out_to_screen = True , spinner = False , env = None , cmpl = False ):
344
+ if env is None :
345
+ env = os .environ
346
+
347
+ if isinstance (cmd_ [0 ], str ):
348
+ cmd_ = [cmd_ [:]]
349
+
350
+ cmd_ = ' && ' .join (' ' .join (c ) for c in cmd_ )
351
+
352
+ que = queue .Queue ()
353
+
354
+ p = subprocess .Popen (
355
+ cmd_ ,
356
+ stdout = subprocess .PIPE ,
357
+ stderr = subprocess .PIPE ,
358
+ shell = True ,
359
+ env = env
360
+ )
361
+
362
+ proc_thread = threading .Thread (
363
+ target = process_output ,
364
+ args = (myprocess , out_to_screen , spinner , cmpl , que )
365
+ )
366
+
367
+ proc_thread .start ()
368
+
369
+ output_buffer = []
370
+
371
+ while proc_thread and proc_thread .is_alive (): # wait for thread to finish
372
+ try :
373
+ line = que .get_nowait () # or q.get(timeout=.1)
374
+ output_buffer .append (line )
375
+ except queue .Empty :
376
+ pass
377
+
378
+ try :
379
+ proc_thread .join (1 )
380
+ except : # NOQA
381
+ break
382
+
383
+ try :
384
+ line = que .get_nowait () # or q.get(timeout=.1)
385
+ output_buffer .append (line )
386
+ except queue .Empty :
387
+ pass
349
388
350
389
if not p .stdout .closed :
351
390
p .stdout .close ()
352
391
353
392
if not p .stderr .closed :
354
393
p .stderr .close ()
355
394
356
- if t is not None :
357
- event .set ()
358
- t .join ()
359
-
360
- sys .stdout .write ('\n ' )
361
- sys .stdout .flush ()
362
-
363
395
output_buffer = '\n ' .join (output_buffer )
364
396
365
397
if out_to_screen :
366
398
if spinner :
367
399
print (output_buffer )
368
- elif cmpl and last_line_len != - 1 :
400
+ elif cmpl :
369
401
sys .stdout .write ('\n ' )
370
402
sys .stdout .flush ()
371
403
0 commit comments