| 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 errno | 8 import errno |
| 9 import logging | 9 import logging |
| 10 import os | 10 import os |
| (...skipping 174 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 185 os.makedirs(tree) | 185 os.makedirs(tree) |
| 186 except OSError, e: | 186 except OSError, e: |
| 187 # 17 POSIX, 183 Windows | 187 # 17 POSIX, 183 Windows |
| 188 if e.errno not in (17, 183): | 188 if e.errno not in (17, 183): |
| 189 raise | 189 raise |
| 190 if count > 40: | 190 if count > 40: |
| 191 # Give up. | 191 # Give up. |
| 192 raise | 192 raise |
| 193 | 193 |
| 194 | 194 |
| 195 def CheckCallAndFilterAndHeader(args, always=False, **kwargs): | 195 def CheckCallAndFilterAndHeader(args, always=False, header=None, **kwargs): |
| 196 """Adds 'header' support to CheckCallAndFilter. | 196 """Adds 'header' support to CheckCallAndFilter. |
| 197 | 197 |
| 198 If |always| is True, a message indicating what is being done | 198 If |always| is True, a message indicating what is being done |
| 199 is printed to stdout all the time even if not output is generated. Otherwise | 199 is printed to stdout all the time even if not output is generated. Otherwise |
| 200 the message header is printed only if the call generated any ouput. | 200 the message header is printed only if the call generated any ouput. |
| 201 """ | 201 """ |
| 202 stdout = kwargs.get('stdout', None) or sys.stdout | 202 stdout = kwargs.setdefault('stdout', sys.stdout) |
| 203 if header is None: |
| 204 header = "\n________ running '%s' in '%s'\n" % ( |
| 205 ' '.join(args), kwargs.get('cwd', '.')) |
| 206 |
| 203 if always: | 207 if always: |
| 204 stdout.write('\n________ running \'%s\' in \'%s\'\n' | 208 stdout.write(header) |
| 205 % (' '.join(args), kwargs.get('cwd', '.'))) | |
| 206 else: | 209 else: |
| 207 filter_fn = kwargs.get('filter_fn', None) | 210 filter_fn = kwargs.get('filter_fn') |
| 208 def filter_msg(line): | 211 def filter_msg(line): |
| 209 if line is None: | 212 if line is None: |
| 210 stdout.write('\n________ running \'%s\' in \'%s\'\n' | 213 stdout.write(header) |
| 211 % (' '.join(args), kwargs.get('cwd', '.'))) | |
| 212 elif filter_fn: | 214 elif filter_fn: |
| 213 filter_fn(line) | 215 filter_fn(line) |
| 214 kwargs['filter_fn'] = filter_msg | 216 kwargs['filter_fn'] = filter_msg |
| 215 kwargs['call_filter_on_first_line'] = True | 217 kwargs['call_filter_on_first_line'] = True |
| 216 # Obviously. | 218 # Obviously. |
| 217 kwargs['print_stdout'] = True | 219 kwargs.setdefault('print_stdout', True) |
| 218 return CheckCallAndFilter(args, **kwargs) | 220 return CheckCallAndFilter(args, **kwargs) |
| 219 | 221 |
| 220 | 222 |
| 221 class Wrapper(object): | 223 class Wrapper(object): |
| 222 """Wraps an object, acting as a transparent proxy for all properties by | 224 """Wraps an object, acting as a transparent proxy for all properties by |
| 223 default. | 225 default. |
| 224 """ | 226 """ |
| 225 def __init__(self, wrapped): | 227 def __init__(self, wrapped): |
| 226 self._wrapped = wrapped | 228 self._wrapped = wrapped |
| 227 | 229 |
| (...skipping 215 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 443 return None | 445 return None |
| 444 # If the root does not have a trailing \ or /, we add it so the returned | 446 # If the root does not have a trailing \ or /, we add it so the returned |
| 445 # path starts immediately after the seperator regardless of whether it is | 447 # path starts immediately after the seperator regardless of whether it is |
| 446 # provided. | 448 # provided. |
| 447 root = os.path.join(root, '') | 449 root = os.path.join(root, '') |
| 448 return subpath[len(root):] | 450 return subpath[len(root):] |
| 449 | 451 |
| 450 | 452 |
| 451 def FindFileUpwards(filename, path=None): | 453 def FindFileUpwards(filename, path=None): |
| 452 """Search upwards from the a directory (default: current) to find a file. | 454 """Search upwards from the a directory (default: current) to find a file. |
| 453 | 455 |
| 454 Returns nearest upper-level directory with the passed in file. | 456 Returns nearest upper-level directory with the passed in file. |
| 455 """ | 457 """ |
| 456 if not path: | 458 if not path: |
| 457 path = os.getcwd() | 459 path = os.getcwd() |
| 458 path = os.path.realpath(path) | 460 path = os.path.realpath(path) |
| 459 while True: | 461 while True: |
| 460 file_path = os.path.join(path, filename) | 462 file_path = os.path.join(path, filename) |
| 461 if os.path.exists(file_path): | 463 if os.path.exists(file_path): |
| 462 return path | 464 return path |
| 463 (new_path, _) = os.path.split(path) | 465 (new_path, _) = os.path.split(path) |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 519 class ExecutionQueue(object): | 521 class ExecutionQueue(object): |
| 520 """Runs a set of WorkItem that have interdependencies and were WorkItem are | 522 """Runs a set of WorkItem that have interdependencies and were WorkItem are |
| 521 added as they are processed. | 523 added as they are processed. |
| 522 | 524 |
| 523 In gclient's case, Dependencies sometime needs to be run out of order due to | 525 In gclient's case, Dependencies sometime needs to be run out of order due to |
| 524 From() keyword. This class manages that all the required dependencies are run | 526 From() keyword. This class manages that all the required dependencies are run |
| 525 before running each one. | 527 before running each one. |
| 526 | 528 |
| 527 Methods of this class are thread safe. | 529 Methods of this class are thread safe. |
| 528 """ | 530 """ |
| 529 def __init__(self, jobs, progress): | 531 def __init__(self, jobs, progress, ignore_requirements): |
| 530 """jobs specifies the number of concurrent tasks to allow. progress is a | 532 """jobs specifies the number of concurrent tasks to allow. progress is a |
| 531 Progress instance.""" | 533 Progress instance.""" |
| 532 # Set when a thread is done or a new item is enqueued. | 534 # Set when a thread is done or a new item is enqueued. |
| 533 self.ready_cond = threading.Condition() | 535 self.ready_cond = threading.Condition() |
| 534 # Maximum number of concurrent tasks. | 536 # Maximum number of concurrent tasks. |
| 535 self.jobs = jobs | 537 self.jobs = jobs |
| 536 # List of WorkItem, for gclient, these are Dependency instances. | 538 # List of WorkItem, for gclient, these are Dependency instances. |
| 537 self.queued = [] | 539 self.queued = [] |
| 538 # List of strings representing each Dependency.name that was run. | 540 # List of strings representing each Dependency.name that was run. |
| 539 self.ran = [] | 541 self.ran = [] |
| 540 # List of items currently running. | 542 # List of items currently running. |
| 541 self.running = [] | 543 self.running = [] |
| 542 # Exceptions thrown if any. | 544 # Exceptions thrown if any. |
| 543 self.exceptions = Queue.Queue() | 545 self.exceptions = Queue.Queue() |
| 544 # Progress status | 546 # Progress status |
| 545 self.progress = progress | 547 self.progress = progress |
| 546 if self.progress: | 548 if self.progress: |
| 547 self.progress.update(0) | 549 self.progress.update(0) |
| 548 | 550 |
| 551 self.ignore_requirements = ignore_requirements |
| 552 |
| 549 def enqueue(self, d): | 553 def enqueue(self, d): |
| 550 """Enqueue one Dependency to be executed later once its requirements are | 554 """Enqueue one Dependency to be executed later once its requirements are |
| 551 satisfied. | 555 satisfied. |
| 552 """ | 556 """ |
| 553 assert isinstance(d, WorkItem) | 557 assert isinstance(d, WorkItem) |
| 554 self.ready_cond.acquire() | 558 self.ready_cond.acquire() |
| 555 try: | 559 try: |
| 556 self.queued.append(d) | 560 self.queued.append(d) |
| 557 total = len(self.queued) + len(self.ran) + len(self.running) | 561 total = len(self.queued) + len(self.ran) + len(self.running) |
| 558 logging.debug('enqueued(%s)' % d.name) | 562 logging.debug('enqueued(%s)' % d.name) |
| (...skipping 17 matching lines...) Expand all Loading... |
| 576 self.queued = [] | 580 self.queued = [] |
| 577 self._flush_terminated_threads() | 581 self._flush_terminated_threads() |
| 578 if (not self.queued and not self.running or | 582 if (not self.queued and not self.running or |
| 579 self.jobs == len(self.running)): | 583 self.jobs == len(self.running)): |
| 580 logging.debug('No more worker threads or can\'t queue anything.') | 584 logging.debug('No more worker threads or can\'t queue anything.') |
| 581 break | 585 break |
| 582 | 586 |
| 583 # Check for new tasks to start. | 587 # Check for new tasks to start. |
| 584 for i in xrange(len(self.queued)): | 588 for i in xrange(len(self.queued)): |
| 585 # Verify its requirements. | 589 # Verify its requirements. |
| 586 for r in self.queued[i].requirements: | 590 if (self.ignore_requirements or |
| 587 if not r in self.ran: | 591 not (set(self.queued[i].requirements) - set(self.ran))): |
| 588 # Requirement not met. | |
| 589 break | |
| 590 else: | |
| 591 # Start one work item: all its requirements are satisfied. | 592 # Start one work item: all its requirements are satisfied. |
| 592 self._run_one_task(self.queued.pop(i), args, kwargs) | 593 self._run_one_task(self.queued.pop(i), args, kwargs) |
| 593 break | 594 break |
| 594 else: | 595 else: |
| 595 # Couldn't find an item that could run. Break out the outher loop. | 596 # Couldn't find an item that could run. Break out the outher loop. |
| 596 break | 597 break |
| 597 | 598 |
| 598 if not self.queued and not self.running: | 599 if not self.queued and not self.running: |
| 599 # We're done. | 600 # We're done. |
| 600 break | 601 break |
| (...skipping 175 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 776 | 777 |
| 777 Python on OSX 10.6 raises a NotImplementedError exception. | 778 Python on OSX 10.6 raises a NotImplementedError exception. |
| 778 """ | 779 """ |
| 779 try: | 780 try: |
| 780 import multiprocessing | 781 import multiprocessing |
| 781 return multiprocessing.cpu_count() | 782 return multiprocessing.cpu_count() |
| 782 except: # pylint: disable=W0702 | 783 except: # pylint: disable=W0702 |
| 783 # Mac OS 10.6 only | 784 # Mac OS 10.6 only |
| 784 # pylint: disable=E1101 | 785 # pylint: disable=E1101 |
| 785 return int(os.sysconf('SC_NPROCESSORS_ONLN')) | 786 return int(os.sysconf('SC_NPROCESSORS_ONLN')) |
| OLD | NEW |