Chromium Code Reviews| 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 cStringIO | 8 import cStringIO |
| 9 import datetime | |
| 9 import logging | 10 import logging |
| 10 import os | 11 import os |
| 11 import pipes | 12 import pipes |
| 12 import platform | 13 import platform |
| 13 import Queue | 14 import Queue |
| 14 import re | 15 import re |
| 15 import stat | 16 import stat |
| 16 import subprocess | 17 import subprocess |
| 17 import sys | 18 import sys |
| 18 import tempfile | 19 import tempfile |
| 19 import threading | 20 import threading |
| 20 import time | 21 import time |
| 21 import urlparse | 22 import urlparse |
| 22 | 23 |
| 23 import subprocess2 | 24 import subprocess2 |
| 24 | 25 |
| 25 | 26 |
| 26 RETRY_MAX = 3 | 27 RETRY_MAX = 3 |
| 27 RETRY_INITIAL_SLEEP = 0.5 | 28 RETRY_INITIAL_SLEEP = 0.5 |
| 29 START = datetime.datetime.now() | |
| 28 | 30 |
| 29 | 31 |
| 30 _WARNINGS = [] | 32 _WARNINGS = [] |
| 31 | 33 |
| 32 | 34 |
| 33 # These repos are known to cause OOM errors on 32-bit platforms, due the the | 35 # These repos are known to cause OOM errors on 32-bit platforms, due the the |
| 34 # very large objects they contain. It is not safe to use threaded index-pack | 36 # very large objects they contain. It is not safe to use threaded index-pack |
| 35 # when cloning/fetching them. | 37 # when cloning/fetching them. |
| 36 THREADED_INDEX_PACK_BLACKLIST = [ | 38 THREADED_INDEX_PACK_BLACKLIST = [ |
| 37 'https://chromium.googlesource.com/chromium/reference_builds/chrome_win.git' | 39 'https://chromium.googlesource.com/chromium/reference_builds/chrome_win.git' |
| 38 ] | 40 ] |
| 39 | 41 |
| 40 | 42 |
| 41 class Error(Exception): | 43 class Error(Exception): |
| 42 """gclient exception class.""" | 44 """gclient exception class.""" |
| 43 def __init__(self, msg, *args, **kwargs): | 45 def __init__(self, msg, *args, **kwargs): |
| 44 index = getattr(threading.currentThread(), 'index', 0) | 46 index = getattr(threading.currentThread(), 'index', 0) |
| 45 if index: | 47 if index: |
| 46 msg = '\n'.join('%d> %s' % (index, l) for l in msg.splitlines()) | 48 msg = '\n'.join('%d> %s' % (index, l) for l in msg.splitlines()) |
| 47 super(Error, self).__init__(msg, *args, **kwargs) | 49 super(Error, self).__init__(msg, *args, **kwargs) |
| 48 | 50 |
| 49 | 51 |
| 52 def Elapsed(until=None): | |
| 53 if until is None: | |
| 54 until = datetime.datetime.now() | |
| 55 return str(until - START).partition('.')[0] | |
| 56 | |
| 57 | |
| 50 def PrintWarnings(): | 58 def PrintWarnings(): |
| 51 """Prints any accumulated warnings.""" | 59 """Prints any accumulated warnings.""" |
| 52 if _WARNINGS: | 60 if _WARNINGS: |
| 53 print >> sys.stderr, '\n\nWarnings:' | 61 print >> sys.stderr, '\n\nWarnings:' |
| 54 for warning in _WARNINGS: | 62 for warning in _WARNINGS: |
| 55 print >> sys.stderr, warning | 63 print >> sys.stderr, warning |
| 56 | 64 |
| 57 | 65 |
| 58 def AddWarning(msg): | 66 def AddWarning(msg): |
| 59 """Adds the given warning message to the list of accumulated warnings.""" | 67 """Adds the given warning message to the list of accumulated warnings.""" |
| (...skipping 416 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 476 try: | 484 try: |
| 477 in_byte = kid.stdout.read(1) | 485 in_byte = kid.stdout.read(1) |
| 478 if in_byte: | 486 if in_byte: |
| 479 if call_filter_on_first_line: | 487 if call_filter_on_first_line: |
| 480 filter_fn(None) | 488 filter_fn(None) |
| 481 in_line = '' | 489 in_line = '' |
| 482 while in_byte: | 490 while in_byte: |
| 483 output.write(in_byte) | 491 output.write(in_byte) |
| 484 if print_stdout: | 492 if print_stdout: |
| 485 stdout.write(in_byte) | 493 stdout.write(in_byte) |
| 486 if in_byte != '\r': | 494 if in_byte not in ['\r', '\n']: |
| 487 if in_byte != '\n': | 495 in_line += in_byte |
| 488 in_line += in_byte | |
| 489 else: | |
| 490 filter_fn(in_line) | |
| 491 in_line = '' | |
| 492 else: | 496 else: |
| 493 filter_fn(in_line) | 497 filter_fn(in_line) |
| 494 in_line = '' | 498 in_line = '' |
| 495 in_byte = kid.stdout.read(1) | 499 in_byte = kid.stdout.read(1) |
| 496 # Flush the rest of buffered output. This is only an issue with | 500 # Flush the rest of buffered output. This is only an issue with |
| 497 # stdout/stderr not ending with a \n. | 501 # stdout/stderr not ending with a \n. |
| 498 if len(in_line): | 502 if len(in_line): |
| 499 filter_fn(in_line) | 503 filter_fn(in_line) |
| 500 rv = kid.wait() | 504 rv = kid.wait() |
| 501 | 505 |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 518 raise subprocess2.CalledProcessError( | 522 raise subprocess2.CalledProcessError( |
| 519 rv, args, kwargs.get('cwd', None), None, None) | 523 rv, args, kwargs.get('cwd', None), None, None) |
| 520 | 524 |
| 521 | 525 |
| 522 class GitFilter(object): | 526 class GitFilter(object): |
| 523 """A filter_fn implementation for quieting down git output messages. | 527 """A filter_fn implementation for quieting down git output messages. |
| 524 | 528 |
| 525 Allows a custom function to skip certain lines (predicate), and will throttle | 529 Allows a custom function to skip certain lines (predicate), and will throttle |
| 526 the output of percentage completed lines to only output every X seconds. | 530 the output of percentage completed lines to only output every X seconds. |
| 527 """ | 531 """ |
| 528 PERCENT_RE = re.compile('.* ([0-9]{1,2})% .*') | 532 PERCENT_RE = re.compile('(.*) ([0-9]{1,3})% .*') |
| 529 | 533 |
| 530 def __init__(self, time_throttle=0, predicate=None): | 534 def __init__(self, time_throttle=0, predicate=None, out_fh=None): |
| 531 """ | 535 """ |
| 532 Args: | 536 Args: |
| 533 time_throttle (int): GitFilter will throttle 'noisy' output (such as the | 537 time_throttle (int): GitFilter will throttle 'noisy' output (such as the |
| 534 XX% complete messages) to only be printed at least |time_throttle| | 538 XX% complete messages) to only be printed at least |time_throttle| |
| 535 seconds apart. | 539 seconds apart. |
| 536 predicate (f(line)): An optional function which is invoked for every line. | 540 predicate (f(line)): An optional function which is invoked for every line. |
| 537 The line will be skipped if predicate(line) returns False. | 541 The line will be skipped if predicate(line) returns False. |
| 542 out_fh: File handle to write output to. | |
| 538 """ | 543 """ |
| 539 self.last_time = 0 | 544 self.last_time = 0 |
| 540 self.time_throttle = time_throttle | 545 self.time_throttle = time_throttle |
| 541 self.predicate = predicate | 546 self.predicate = predicate |
| 547 self.out_fh = out_fh or sys.stdout | |
| 548 self.progress_prefix = None | |
| 542 | 549 |
| 543 def __call__(self, line): | 550 def __call__(self, line): |
| 544 # git uses an escape sequence to clear the line; elide it. | 551 # git uses an escape sequence to clear the line; elide it. |
| 545 esc = line.find(unichr(033)) | 552 esc = line.find(unichr(033)) |
| 546 if esc > -1: | 553 if esc > -1: |
| 547 line = line[:esc] | 554 line = line[:esc] |
| 548 if self.predicate and not self.predicate(line): | 555 if self.predicate and not self.predicate(line): |
| 549 return | 556 return |
| 550 now = time.time() | 557 now = time.time() |
| 551 match = self.PERCENT_RE.match(line) | 558 match = self.PERCENT_RE.match(line) |
| 552 if not match: | 559 if match: |
| 553 self.last_time = 0 | 560 if match.group(1) != self.progress_prefix: |
| 554 if (now - self.last_time) >= self.time_throttle: | 561 self.progress_prefix = match.group(1) |
| 555 self.last_time = now | 562 elif now - self.last_time < self.time_throttle: |
| 556 print line | 563 return |
| 564 self.last_time = now | |
| 565 self.out_fh.write('[%s] ' % Elapsed()) | |
| 566 print >> self.out_fh, line | |
| 557 | 567 |
| 558 | 568 |
| 559 def FindGclientRoot(from_dir, filename='.gclient'): | 569 def FindGclientRoot(from_dir, filename='.gclient'): |
| 560 """Tries to find the gclient root.""" | 570 """Tries to find the gclient root.""" |
| 561 real_from_dir = os.path.realpath(from_dir) | 571 real_from_dir = os.path.realpath(from_dir) |
| 562 path = real_from_dir | 572 path = real_from_dir |
| 563 while not os.path.exists(os.path.join(path, filename)): | 573 while not os.path.exists(os.path.join(path, filename)): |
| 564 split_path = os.path.split(path) | 574 split_path = os.path.split(path) |
| 565 if not split_path[1]: | 575 if not split_path[1]: |
| 566 return None | 576 return None |
| (...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 676 class WorkItem(object): | 686 class WorkItem(object): |
| 677 """One work item.""" | 687 """One work item.""" |
| 678 # On cygwin, creating a lock throwing randomly when nearing ~100 locks. | 688 # On cygwin, creating a lock throwing randomly when nearing ~100 locks. |
| 679 # As a workaround, use a single lock. Yep you read it right. Single lock for | 689 # As a workaround, use a single lock. Yep you read it right. Single lock for |
| 680 # all the 100 objects. | 690 # all the 100 objects. |
| 681 lock = threading.Lock() | 691 lock = threading.Lock() |
| 682 | 692 |
| 683 def __init__(self, name): | 693 def __init__(self, name): |
| 684 # A unique string representing this work item. | 694 # A unique string representing this work item. |
| 685 self._name = name | 695 self._name = name |
| 696 self.outbuf = cStringIO.StringIO() | |
| 686 | 697 |
| 687 def run(self, work_queue): | 698 def run(self, work_queue): |
| 688 """work_queue is passed as keyword argument so it should be | 699 """work_queue is passed as keyword argument so it should be |
| 689 the last parameters of the function when you override it.""" | 700 the last parameters of the function when you override it.""" |
| 690 pass | 701 pass |
| 691 | 702 |
| 692 @property | 703 @property |
| 693 def name(self): | 704 def name(self): |
| 694 return self._name | 705 return self._name |
| 695 | 706 |
| 696 | 707 |
| 697 class ExecutionQueue(object): | 708 class ExecutionQueue(object): |
| 698 """Runs a set of WorkItem that have interdependencies and were WorkItem are | 709 """Runs a set of WorkItem that have interdependencies and were WorkItem are |
| 699 added as they are processed. | 710 added as they are processed. |
| 700 | 711 |
| 701 In gclient's case, Dependencies sometime needs to be run out of order due to | 712 In gclient's case, Dependencies sometime needs to be run out of order due to |
| 702 From() keyword. This class manages that all the required dependencies are run | 713 From() keyword. This class manages that all the required dependencies are run |
| 703 before running each one. | 714 before running each one. |
| 704 | 715 |
| 705 Methods of this class are thread safe. | 716 Methods of this class are thread safe. |
| 706 """ | 717 """ |
| 707 def __init__(self, jobs, progress, ignore_requirements): | 718 def __init__(self, jobs, progress, ignore_requirements, verbose=False): |
| 708 """jobs specifies the number of concurrent tasks to allow. progress is a | 719 """jobs specifies the number of concurrent tasks to allow. progress is a |
| 709 Progress instance.""" | 720 Progress instance.""" |
| 710 # Set when a thread is done or a new item is enqueued. | 721 # Set when a thread is done or a new item is enqueued. |
| 711 self.ready_cond = threading.Condition() | 722 self.ready_cond = threading.Condition() |
| 712 # Maximum number of concurrent tasks. | 723 # Maximum number of concurrent tasks. |
| 713 self.jobs = jobs | 724 self.jobs = jobs |
| 714 # List of WorkItem, for gclient, these are Dependency instances. | 725 # List of WorkItem, for gclient, these are Dependency instances. |
| 715 self.queued = [] | 726 self.queued = [] |
| 716 # List of strings representing each Dependency.name that was run. | 727 # List of strings representing each Dependency.name that was run. |
| 717 self.ran = [] | 728 self.ran = [] |
| 718 # List of items currently running. | 729 # List of items currently running. |
| 719 self.running = [] | 730 self.running = [] |
| 720 # Exceptions thrown if any. | 731 # Exceptions thrown if any. |
| 721 self.exceptions = Queue.Queue() | 732 self.exceptions = Queue.Queue() |
| 722 # Progress status | 733 # Progress status |
| 723 self.progress = progress | 734 self.progress = progress |
| 724 if self.progress: | 735 if self.progress: |
| 725 self.progress.update(0) | 736 self.progress.update(0) |
| 726 | 737 |
| 727 self.ignore_requirements = ignore_requirements | 738 self.ignore_requirements = ignore_requirements |
| 739 self.verbose = verbose | |
| 740 self.last_join = None | |
| 741 self.last_subproc_output = None | |
| 728 | 742 |
| 729 def enqueue(self, d): | 743 def enqueue(self, d): |
| 730 """Enqueue one Dependency to be executed later once its requirements are | 744 """Enqueue one Dependency to be executed later once its requirements are |
| 731 satisfied. | 745 satisfied. |
| 732 """ | 746 """ |
| 733 assert isinstance(d, WorkItem) | 747 assert isinstance(d, WorkItem) |
| 734 self.ready_cond.acquire() | 748 self.ready_cond.acquire() |
| 735 try: | 749 try: |
| 736 self.queued.append(d) | 750 self.queued.append(d) |
| 737 total = len(self.queued) + len(self.ran) + len(self.running) | 751 total = len(self.queued) + len(self.ran) + len(self.running) |
| 738 logging.debug('enqueued(%s)' % d.name) | 752 logging.debug('enqueued(%s)' % d.name) |
| 739 if self.progress: | 753 if self.progress: |
| 740 self.progress._total = total + 1 | 754 self.progress._total = total + 1 |
| 741 self.progress.update(0) | 755 self.progress.update(0) |
| 742 self.ready_cond.notifyAll() | 756 self.ready_cond.notifyAll() |
| 743 finally: | 757 finally: |
| 744 self.ready_cond.release() | 758 self.ready_cond.release() |
| 745 | 759 |
| 760 def out_cb(self, _): | |
|
Ryan Tseng
2014/04/07 20:56:38
What does "cb" stand for?
szager1
2014/04/08 20:41:14
CallBack
| |
| 761 self.last_subproc_output = datetime.datetime.now() | |
| 762 return True | |
| 763 | |
| 764 @staticmethod | |
| 765 def format_task_output(task, comment=''): | |
| 766 if comment: | |
| 767 comment = ' (%s)' % comment | |
| 768 return """ | |
| 769 %s%s | |
| 770 ---------------------------------------- | |
| 771 %s | |
| 772 ---------------------------------------- """ % ( | |
| 773 task.name, comment, task.outbuf.getvalue()) | |
|
Ryan Tseng
2014/04/07 20:56:38
trim task.outbuf.getvalue(), there seems to be an
szager1
2014/04/08 20:41:14
Done.
| |
| 774 | |
| 746 def flush(self, *args, **kwargs): | 775 def flush(self, *args, **kwargs): |
| 747 """Runs all enqueued items until all are executed.""" | 776 """Runs all enqueued items until all are executed.""" |
| 748 kwargs['work_queue'] = self | 777 kwargs['work_queue'] = self |
| 778 self.last_subproc_output = self.last_join = datetime.datetime.now() | |
| 749 self.ready_cond.acquire() | 779 self.ready_cond.acquire() |
| 750 try: | 780 try: |
| 751 while True: | 781 while True: |
| 752 # Check for task to run first, then wait. | 782 # Check for task to run first, then wait. |
| 753 while True: | 783 while True: |
| 754 if not self.exceptions.empty(): | 784 if not self.exceptions.empty(): |
| 755 # Systematically flush the queue when an exception logged. | 785 # Systematically flush the queue when an exception logged. |
| 756 self.queued = [] | 786 self.queued = [] |
| 757 self._flush_terminated_threads() | 787 self._flush_terminated_threads() |
| 758 if (not self.queued and not self.running or | 788 if (not self.queued and not self.running or |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 771 else: | 801 else: |
| 772 # Couldn't find an item that could run. Break out the outher loop. | 802 # Couldn't find an item that could run. Break out the outher loop. |
| 773 break | 803 break |
| 774 | 804 |
| 775 if not self.queued and not self.running: | 805 if not self.queued and not self.running: |
| 776 # We're done. | 806 # We're done. |
| 777 break | 807 break |
| 778 # We need to poll here otherwise Ctrl-C isn't processed. | 808 # We need to poll here otherwise Ctrl-C isn't processed. |
| 779 try: | 809 try: |
| 780 self.ready_cond.wait(10) | 810 self.ready_cond.wait(10) |
| 811 # If we haven't printed to terminal for a while, but we have received | |
| 812 # spew from a suprocess, let the user know we're still progressing. | |
| 813 now = datetime.datetime.now() | |
|
Ryan Tseng
2014/04/07 20:56:38
nit: time.time()? To match timekeeping style earli
szager1
2014/04/08 20:41:14
Nice thing about datetime is the elegant arithmeti
| |
| 814 if (now - self.last_join > datetime.timedelta(seconds=60) and | |
| 815 self.last_subproc_output > self.last_join): | |
| 816 if self.progress: | |
| 817 print >> sys.stdout, '' | |
| 818 print >> sys.stdout, '[%s] Still working...' % Elapsed() | |
|
Ryan Tseng
2014/04/07 20:56:38
Not always clear what process is causing this to p
szager1
2014/04/08 20:41:14
Done.
| |
| 781 except KeyboardInterrupt: | 819 except KeyboardInterrupt: |
| 782 # Help debugging by printing some information: | 820 # Help debugging by printing some information: |
| 783 print >> sys.stderr, ( | 821 print >> sys.stderr, ( |
| 784 ('\nAllowed parallel jobs: %d\n# queued: %d\nRan: %s\n' | 822 ('\nAllowed parallel jobs: %d\n# queued: %d\nRan: %s\n' |
| 785 'Running: %d') % ( | 823 'Running: %d') % ( |
| 786 self.jobs, | 824 self.jobs, |
| 787 len(self.queued), | 825 len(self.queued), |
| 788 ', '.join(self.ran), | 826 ', '.join(self.ran), |
| 789 len(self.running))) | 827 len(self.running))) |
| 790 for i in self.queued: | 828 for i in self.queued: |
| 791 print >> sys.stderr, '%s: %s' % (i.name, ', '.join(i.requirements)) | 829 print >> sys.stderr, '%s (not started): %s' % ( |
| 830 i.name, ', '.join(i.requirements)) | |
| 831 for i in self.running: | |
| 832 print >> sys.stderr, self.format_task_output(i.item, 'interrupted') | |
| 792 raise | 833 raise |
| 793 # Something happened: self.enqueue() or a thread terminated. Loop again. | 834 # Something happened: self.enqueue() or a thread terminated. Loop again. |
| 794 finally: | 835 finally: |
| 795 self.ready_cond.release() | 836 self.ready_cond.release() |
| 796 | 837 |
| 797 assert not self.running, 'Now guaranteed to be single-threaded' | 838 assert not self.running, 'Now guaranteed to be single-threaded' |
| 798 if not self.exceptions.empty(): | 839 if not self.exceptions.empty(): |
| 840 if self.progress: | |
| 841 sys.stdout.write('\n') | |
|
Ryan Tseng
2014/04/07 20:56:38
nit: print >> sys.stdout, '', to match print style
szager1
2014/04/08 20:41:14
Done.
| |
| 799 # To get back the stack location correctly, the raise a, b, c form must be | 842 # To get back the stack location correctly, the raise a, b, c form must be |
| 800 # used, passing a tuple as the first argument doesn't work. | 843 # used, passing a tuple as the first argument doesn't work. |
| 801 e = self.exceptions.get() | 844 e, task = self.exceptions.get() |
| 845 print >> sys.stderr, self.format_task_output(task.item, 'ERROR') | |
| 802 raise e[0], e[1], e[2] | 846 raise e[0], e[1], e[2] |
| 803 if self.progress: | 847 elif self.progress: |
| 804 self.progress.end() | 848 self.progress.end() |
| 805 | 849 |
| 806 def _flush_terminated_threads(self): | 850 def _flush_terminated_threads(self): |
| 807 """Flush threads that have terminated.""" | 851 """Flush threads that have terminated.""" |
| 808 running = self.running | 852 running = self.running |
| 809 self.running = [] | 853 self.running = [] |
| 810 for t in running: | 854 for t in running: |
| 811 if t.isAlive(): | 855 if t.isAlive(): |
| 812 self.running.append(t) | 856 self.running.append(t) |
| 813 else: | 857 else: |
| 814 t.join() | 858 t.join() |
| 859 self.last_join = datetime.datetime.now() | |
| 815 sys.stdout.flush() | 860 sys.stdout.flush() |
| 861 if self.verbose: | |
| 862 print >> sys.stdout, self.format_task_output(t.item) | |
|
Ryan Tseng
2014/04/07 20:56:38
I think it'd be useful to also print the # of minu
szager1
2014/04/08 20:41:14
Done.
| |
| 816 if self.progress: | 863 if self.progress: |
| 817 self.progress.update(1, t.item.name) | 864 self.progress.update(1, t.item.name) |
| 818 if t.item.name in self.ran: | 865 if t.item.name in self.ran: |
| 819 raise Error( | 866 raise Error( |
| 820 'gclient is confused, "%s" is already in "%s"' % ( | 867 'gclient is confused, "%s" is already in "%s"' % ( |
| 821 t.item.name, ', '.join(self.ran))) | 868 t.item.name, ', '.join(self.ran))) |
| 822 if not t.item.name in self.ran: | 869 if not t.item.name in self.ran: |
| 823 self.ran.append(t.item.name) | 870 self.ran.append(t.item.name) |
| 824 | 871 |
| 825 def _run_one_task(self, task_item, args, kwargs): | 872 def _run_one_task(self, task_item, args, kwargs): |
| 826 if self.jobs > 1: | 873 if self.jobs > 1: |
| 827 # Start the thread. | 874 # Start the thread. |
| 828 index = len(self.ran) + len(self.running) + 1 | 875 index = len(self.ran) + len(self.running) + 1 |
| 829 new_thread = self._Worker(task_item, index, args, kwargs) | 876 new_thread = self._Worker(task_item, index, args, kwargs) |
| 830 self.running.append(new_thread) | 877 self.running.append(new_thread) |
| 831 new_thread.start() | 878 new_thread.start() |
| 832 else: | 879 else: |
| 833 # Run the 'thread' inside the main thread. Don't try to catch any | 880 # Run the 'thread' inside the main thread. Don't try to catch any |
| 834 # exception. | 881 # exception. |
| 835 task_item.run(*args, **kwargs) | 882 try: |
| 836 self.ran.append(task_item.name) | 883 task_item.run(*args, **kwargs) |
| 837 if self.progress: | 884 self.ran.append(task_item.name) |
| 838 self.progress.update(1, ', '.join(t.item.name for t in self.running)) | 885 if self.verbose: |
| 886 if self.progress: | |
| 887 print >> sys.stdout, '' | |
| 888 print >> sys.stdout, self.format_task_output(task_item) | |
| 889 if self.progress: | |
| 890 self.progress.update(1, ', '.join(t.item.name for t in self.running)) | |
| 891 except KeyboardInterrupt: | |
| 892 print >> sys.stderr, self.format_task_output(task_item, 'interrupted') | |
| 893 raise | |
| 894 except Exception: | |
| 895 print >> sys.stderr, self.format_task_output(task_item, 'ERROR') | |
| 896 raise | |
| 897 | |
| 839 | 898 |
| 840 class _Worker(threading.Thread): | 899 class _Worker(threading.Thread): |
| 841 """One thread to execute one WorkItem.""" | 900 """One thread to execute one WorkItem.""" |
| 842 def __init__(self, item, index, args, kwargs): | 901 def __init__(self, item, index, args, kwargs): |
| 843 threading.Thread.__init__(self, name=item.name or 'Worker') | 902 threading.Thread.__init__(self, name=item.name or 'Worker') |
| 844 logging.info('_Worker(%s) reqs:%s' % (item.name, item.requirements)) | 903 logging.info('_Worker(%s) reqs:%s' % (item.name, item.requirements)) |
| 845 self.item = item | 904 self.item = item |
| 846 self.index = index | 905 self.index = index |
| 847 self.args = args | 906 self.args = args |
| 848 self.kwargs = kwargs | 907 self.kwargs = kwargs |
| 849 self.daemon = True | 908 self.daemon = True |
| 850 | 909 |
| 851 def run(self): | 910 def run(self): |
| 852 """Runs in its own thread.""" | 911 """Runs in its own thread.""" |
| 853 logging.debug('_Worker.run(%s)' % self.item.name) | 912 logging.debug('_Worker.run(%s)' % self.item.name) |
| 854 work_queue = self.kwargs['work_queue'] | 913 work_queue = self.kwargs['work_queue'] |
| 855 try: | 914 try: |
| 856 self.item.run(*self.args, **self.kwargs) | 915 self.item.run(*self.args, **self.kwargs) |
| 857 except KeyboardInterrupt: | 916 except KeyboardInterrupt: |
| 858 logging.info('Caught KeyboardInterrupt in thread %s', self.item.name) | 917 logging.info('Caught KeyboardInterrupt in thread %s', self.item.name) |
| 859 logging.info(str(sys.exc_info())) | 918 logging.info(str(sys.exc_info())) |
| 860 work_queue.exceptions.put(sys.exc_info()) | 919 work_queue.exceptions.put((sys.exc_info(), self)) |
| 861 raise | 920 raise |
| 862 except Exception: | 921 except Exception: |
| 863 # Catch exception location. | 922 # Catch exception location. |
| 864 logging.info('Caught exception in thread %s', self.item.name) | 923 logging.info('Caught exception in thread %s', self.item.name) |
| 865 logging.info(str(sys.exc_info())) | 924 logging.info(str(sys.exc_info())) |
| 866 work_queue.exceptions.put(sys.exc_info()) | 925 work_queue.exceptions.put((sys.exc_info(), self)) |
| 867 finally: | 926 finally: |
| 868 logging.info('_Worker.run(%s) done', self.item.name) | 927 logging.info('_Worker.run(%s) done', self.item.name) |
| 869 work_queue.ready_cond.acquire() | 928 work_queue.ready_cond.acquire() |
| 870 try: | 929 try: |
| 871 work_queue.ready_cond.notifyAll() | 930 work_queue.ready_cond.notifyAll() |
| 872 finally: | 931 finally: |
| 873 work_queue.ready_cond.release() | 932 work_queue.ready_cond.release() |
| 874 | 933 |
| 875 | 934 |
| 876 def GetEditor(git, git_editor=None): | 935 def GetEditor(git, git_editor=None): |
| (...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1001 def DefaultIndexPackConfig(url=''): | 1060 def DefaultIndexPackConfig(url=''): |
| 1002 """Return reasonable default values for configuring git-index-pack. | 1061 """Return reasonable default values for configuring git-index-pack. |
| 1003 | 1062 |
| 1004 Experiments suggest that higher values for pack.threads don't improve | 1063 Experiments suggest that higher values for pack.threads don't improve |
| 1005 performance.""" | 1064 performance.""" |
| 1006 cache_limit = DefaultDeltaBaseCacheLimit() | 1065 cache_limit = DefaultDeltaBaseCacheLimit() |
| 1007 result = ['-c', 'core.deltaBaseCacheLimit=%s' % cache_limit] | 1066 result = ['-c', 'core.deltaBaseCacheLimit=%s' % cache_limit] |
| 1008 if url in THREADED_INDEX_PACK_BLACKLIST: | 1067 if url in THREADED_INDEX_PACK_BLACKLIST: |
| 1009 result.extend(['-c', 'pack.threads=1']) | 1068 result.extend(['-c', 'pack.threads=1']) |
| 1010 return result | 1069 return result |
| OLD | NEW |