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 |