OLD | NEW |
1 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 # Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 # Use of this source code is governed by a BSD-style license that can be | 2 # Use of this source code is governed by a BSD-style license that can be |
3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
4 | 4 |
5 """Generic utils.""" | 5 """Generic utils.""" |
6 | 6 |
7 import codecs | 7 import codecs |
8 import logging | 8 import logging |
9 import os | 9 import os |
10 import pipes | 10 import pipes |
(...skipping 389 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
400 | 400 |
401 with GCLIENT_CHILDREN_LOCK: | 401 with GCLIENT_CHILDREN_LOCK: |
402 if GCLIENT_CHILDREN: | 402 if GCLIENT_CHILDREN: |
403 print >> sys.stderr, 'Could not kill the following subprocesses:' | 403 print >> sys.stderr, 'Could not kill the following subprocesses:' |
404 for zombie in GCLIENT_CHILDREN: | 404 for zombie in GCLIENT_CHILDREN: |
405 print >> sys.stderr, ' ', zombie.pid | 405 print >> sys.stderr, ' ', zombie.pid |
406 | 406 |
407 | 407 |
408 def CheckCallAndFilter(args, stdout=None, filter_fn=None, | 408 def CheckCallAndFilter(args, stdout=None, filter_fn=None, |
409 print_stdout=None, call_filter_on_first_line=False, | 409 print_stdout=None, call_filter_on_first_line=False, |
410 nag_timer=None, nag_max=None, **kwargs): | 410 **kwargs): |
411 """Runs a command and calls back a filter function if needed. | 411 """Runs a command and calls back a filter function if needed. |
412 | 412 |
413 Accepts all subprocess2.Popen() parameters plus: | 413 Accepts all subprocess2.Popen() parameters plus: |
414 print_stdout: If True, the command's stdout is forwarded to stdout. | 414 print_stdout: If True, the command's stdout is forwarded to stdout. |
415 filter_fn: A function taking a single string argument called with each line | 415 filter_fn: A function taking a single string argument called with each line |
416 of the subprocess2's output. Each line has the trailing newline | 416 of the subprocess2's output. Each line has the trailing newline |
417 character trimmed. | 417 character trimmed. |
418 stdout: Can be any bufferable output. | 418 stdout: Can be any bufferable output. |
419 | 419 |
420 stderr is always redirected to stdout. | 420 stderr is always redirected to stdout. |
421 """ | 421 """ |
422 assert print_stdout or filter_fn | 422 assert print_stdout or filter_fn |
423 stdout = stdout or sys.stdout | 423 stdout = stdout or sys.stdout |
424 filter_fn = filter_fn or (lambda x: None) | 424 filter_fn = filter_fn or (lambda x: None) |
425 kid = subprocess2.Popen( | 425 kid = subprocess2.Popen( |
426 args, bufsize=0, stdout=subprocess2.PIPE, stderr=subprocess2.STDOUT, | 426 args, bufsize=0, stdout=subprocess2.PIPE, stderr=subprocess2.STDOUT, |
427 **kwargs) | 427 **kwargs) |
428 | 428 |
429 GClientChildren.add(kid) | 429 GClientChildren.add(kid) |
430 | 430 |
431 # Do a flush of stdout before we begin reading from the subprocess2's stdout | 431 # Do a flush of stdout before we begin reading from the subprocess2's stdout |
432 stdout.flush() | 432 stdout.flush() |
433 | 433 |
434 nag = None | |
435 if nag_timer: | |
436 # Hack thread.index to force correct annotation. | |
437 index = getattr(threading.currentThread(), 'index', 0) | |
438 def _nag_cb(elapsed): | |
439 setattr(threading.currentThread(), 'index', index) | |
440 stdout.write(' No output for %.0f seconds from command:\n' % elapsed) | |
441 stdout.write(' %s\n' % kid.cmd_str) | |
442 if (nag_max and | |
443 int('%.0f' % (elapsed / nag_timer)) >= nag_max): | |
444 stdout.write(' ... killing it!\n') | |
445 kid.kill() | |
446 nag = subprocess2.NagTimer(nag_timer, _nag_cb) | |
447 nag.start() | |
448 | |
449 # Also, we need to forward stdout to prevent weird re-ordering of output. | 434 # Also, we need to forward stdout to prevent weird re-ordering of output. |
450 # This has to be done on a per byte basis to make sure it is not buffered: | 435 # This has to be done on a per byte basis to make sure it is not buffered: |
451 # normally buffering is done for each line, but if svn requests input, no | 436 # normally buffering is done for each line, but if svn requests input, no |
452 # end-of-line character is output after the prompt and it would not show up. | 437 # end-of-line character is output after the prompt and it would not show up. |
453 try: | 438 try: |
454 in_byte = kid.stdout.read(1) | 439 in_byte = kid.stdout.read(1) |
455 if in_byte: | 440 if in_byte: |
456 if nag: | |
457 nag.event() | |
458 if call_filter_on_first_line: | 441 if call_filter_on_first_line: |
459 filter_fn(None) | 442 filter_fn(None) |
460 in_line = '' | 443 in_line = '' |
461 while in_byte: | 444 while in_byte: |
462 if in_byte != '\r': | 445 if in_byte != '\r': |
463 if print_stdout: | 446 if print_stdout: |
464 stdout.write(in_byte) | 447 stdout.write(in_byte) |
465 if in_byte != '\n': | 448 if in_byte != '\n': |
466 in_line += in_byte | 449 in_line += in_byte |
467 else: | 450 else: |
468 filter_fn(in_line) | 451 filter_fn(in_line) |
469 in_line = '' | 452 in_line = '' |
470 else: | 453 else: |
471 filter_fn(in_line) | 454 filter_fn(in_line) |
472 in_line = '' | 455 in_line = '' |
473 in_byte = kid.stdout.read(1) | 456 in_byte = kid.stdout.read(1) |
474 if in_byte and nag: | |
475 nag.event() | |
476 # Flush the rest of buffered output. This is only an issue with | 457 # Flush the rest of buffered output. This is only an issue with |
477 # stdout/stderr not ending with a \n. | 458 # stdout/stderr not ending with a \n. |
478 if len(in_line): | 459 if len(in_line): |
479 filter_fn(in_line) | 460 filter_fn(in_line) |
480 rv = kid.wait() | 461 rv = kid.wait() |
481 | 462 |
482 # Don't put this in a 'finally,' since the child may still run if we get an | 463 # Don't put this in a 'finally,' since the child may still run if we get an |
483 # exception. | 464 # exception. |
484 GClientChildren.remove(kid) | 465 GClientChildren.remove(kid) |
485 | 466 |
486 except KeyboardInterrupt: | 467 except KeyboardInterrupt: |
487 print >> sys.stderr, 'Failed while running "%s"' % ' '.join(args) | 468 print >> sys.stderr, 'Failed while running "%s"' % ' '.join(args) |
488 raise | 469 raise |
489 finally: | |
490 if nag: | |
491 nag.cancel() | |
492 | 470 |
493 if rv: | 471 if rv: |
494 raise subprocess2.CalledProcessError( | 472 raise subprocess2.CalledProcessError( |
495 rv, args, kwargs.get('cwd', None), None, None) | 473 rv, args, kwargs.get('cwd', None), None, None) |
496 return 0 | 474 return 0 |
497 | 475 |
498 | 476 |
499 def FindGclientRoot(from_dir, filename='.gclient'): | 477 def FindGclientRoot(from_dir, filename='.gclient'): |
500 """Tries to find the gclient root.""" | 478 """Tries to find the gclient root.""" |
501 real_from_dir = os.path.realpath(from_dir) | 479 real_from_dir = os.path.realpath(from_dir) |
(...skipping 398 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
900 | 878 |
901 Python on OSX 10.6 raises a NotImplementedError exception. | 879 Python on OSX 10.6 raises a NotImplementedError exception. |
902 """ | 880 """ |
903 try: | 881 try: |
904 import multiprocessing | 882 import multiprocessing |
905 return multiprocessing.cpu_count() | 883 return multiprocessing.cpu_count() |
906 except: # pylint: disable=W0702 | 884 except: # pylint: disable=W0702 |
907 # Mac OS 10.6 only | 885 # Mac OS 10.6 only |
908 # pylint: disable=E1101 | 886 # pylint: disable=E1101 |
909 return int(os.sysconf('SC_NPROCESSORS_ONLN')) | 887 return int(os.sysconf('SC_NPROCESSORS_ONLN')) |
OLD | NEW |