OLD | NEW |
1 # Copyright 2009 Google Inc. All Rights Reserved. | 1 # Copyright 2009 Google Inc. All Rights Reserved. |
2 # | 2 # |
3 # Licensed under the Apache License, Version 2.0 (the "License"); | 3 # Licensed under the Apache License, Version 2.0 (the "License"); |
4 # you may not use this file except in compliance with the License. | 4 # you may not use this file except in compliance with the License. |
5 # You may obtain a copy of the License at | 5 # You may obtain a copy of the License at |
6 # | 6 # |
7 # http://www.apache.org/licenses/LICENSE-2.0 | 7 # http://www.apache.org/licenses/LICENSE-2.0 |
8 # | 8 # |
9 # Unless required by applicable law or agreed to in writing, software | 9 # Unless required by applicable law or agreed to in writing, software |
10 # distributed under the License is distributed on an "AS IS" BASIS, | 10 # distributed under the License is distributed on an "AS IS" BASIS, |
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
12 # See the License for the specific language governing permissions and | 12 # See the License for the specific language governing permissions and |
13 # limitations under the License. | 13 # limitations under the License. |
14 | 14 |
15 """Generic utils.""" | 15 """Generic utils.""" |
16 | 16 |
17 import errno | 17 import errno |
18 import logging | 18 import logging |
19 import os | 19 import os |
20 import re | 20 import re |
21 import stat | 21 import stat |
22 import subprocess | 22 import subprocess |
23 import sys | 23 import sys |
24 import time | 24 import time |
| 25 import threading |
25 import xml.dom.minidom | 26 import xml.dom.minidom |
26 import xml.parsers.expat | 27 import xml.parsers.expat |
27 | 28 |
28 | 29 |
29 class CheckCallError(OSError): | 30 class CheckCallError(OSError): |
30 """CheckCall() returned non-0.""" | 31 """CheckCall() returned non-0.""" |
31 def __init__(self, command, cwd, retcode, stdout, stderr=None): | 32 def __init__(self, command, cwd, retcode, stdout, stderr=None): |
32 OSError.__init__(self, command, cwd, retcode, stdout, stderr) | 33 OSError.__init__(self, command, cwd, retcode, stdout, stderr) |
33 self.command = command | 34 self.command = command |
34 self.cwd = cwd | 35 self.cwd = cwd |
(...skipping 321 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
356 config_path = FindFileUpwards(config_file, path) | 357 config_path = FindFileUpwards(config_file, path) |
357 | 358 |
358 if not config_path: | 359 if not config_path: |
359 print "Can't find %s" % config_file | 360 print "Can't find %s" % config_file |
360 return None | 361 return None |
361 | 362 |
362 env = {} | 363 env = {} |
363 execfile(config_path, env) | 364 execfile(config_path, env) |
364 config_dir = os.path.dirname(config_path) | 365 config_dir = os.path.dirname(config_path) |
365 return config_dir, env['entries'] | 366 return config_dir, env['entries'] |
| 367 |
| 368 |
| 369 class WorkItem(object): |
| 370 """One work item.""" |
| 371 # A list of string, each being a WorkItem name. |
| 372 requirements = [] |
| 373 # A unique string representing this work item. |
| 374 name = None |
| 375 |
| 376 def run(self): |
| 377 pass |
| 378 |
| 379 |
| 380 class ExecutionQueue(object): |
| 381 """Dependencies sometime needs to be run out of order due to From() keyword. |
| 382 |
| 383 This class manages that all the required dependencies are run before running |
| 384 each one. |
| 385 |
| 386 Methods of this class are multithread safe. |
| 387 """ |
| 388 def __init__(self, progress): |
| 389 self.lock = threading.Lock() |
| 390 # List of WorkItem, Dependency inherits from WorkItem. |
| 391 self.queued = [] |
| 392 # List of strings representing each Dependency.name that was run. |
| 393 self.ran = [] |
| 394 # List of items currently running. |
| 395 self.running = [] |
| 396 self.progress = progress |
| 397 if self.progress: |
| 398 self.progress.update() |
| 399 |
| 400 def enqueue(self, d): |
| 401 """Enqueue one Dependency to be executed later once its requirements are |
| 402 satisfied. |
| 403 """ |
| 404 assert isinstance(d, WorkItem) |
| 405 try: |
| 406 self.lock.acquire() |
| 407 self.queued.append(d) |
| 408 total = len(self.queued) + len(self.ran) + len(self.running) |
| 409 finally: |
| 410 self.lock.release() |
| 411 if self.progress: |
| 412 self.progress._total = total + 1 |
| 413 self.progress.update(0) |
| 414 |
| 415 def flush(self, *args, **kwargs): |
| 416 """Runs all enqueued items until all are executed.""" |
| 417 while self._run_one_item(*args, **kwargs): |
| 418 pass |
| 419 queued = [] |
| 420 running = [] |
| 421 try: |
| 422 self.lock.acquire() |
| 423 if self.queued: |
| 424 queued = self.queued |
| 425 self.queued = [] |
| 426 if self.running: |
| 427 running = self.running |
| 428 self.running = [] |
| 429 finally: |
| 430 self.lock.release() |
| 431 if self.progress: |
| 432 self.progress.end() |
| 433 if queued: |
| 434 raise gclient_utils.Error('Entries still queued: %s' % str(queued)) |
| 435 if running: |
| 436 raise gclient_utils.Error('Entries still queued: %s' % str(running)) |
| 437 |
| 438 def _run_one_item(self, *args, **kwargs): |
| 439 """Removes one item from the queue that has all its requirements completed |
| 440 and execute it. |
| 441 |
| 442 Returns False if no item could be run. |
| 443 """ |
| 444 i = 0 |
| 445 d = None |
| 446 try: |
| 447 self.lock.acquire() |
| 448 while i != len(self.queued) and not d: |
| 449 d = self.queued.pop(i) |
| 450 for r in d.requirements: |
| 451 if not r in self.ran: |
| 452 self.queued.insert(i, d) |
| 453 d = None |
| 454 break |
| 455 i += 1 |
| 456 if not d: |
| 457 return False |
| 458 self.running.append(d) |
| 459 finally: |
| 460 self.lock.release() |
| 461 d.run(*args, **kwargs) |
| 462 try: |
| 463 self.lock.acquire() |
| 464 assert not d.name in self.ran |
| 465 if not d.name in self.ran: |
| 466 self.ran.append(d.name) |
| 467 self.running.remove(d) |
| 468 if self.progress: |
| 469 self.progress.update(1) |
| 470 finally: |
| 471 self.lock.release() |
| 472 return True |
OLD | NEW |