Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(98)

Side by Side Diff: gclient_utils.py

Issue 1640001: Add -j option to gclient to run parallel updates (Closed)
Patch Set: update to tot Created 10 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « gclient.py ('k') | tests/gclient_utils_test.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 from third_party.repo.progress import Progress
21 import Queue
20 import re 22 import re
21 import stat 23 import stat
22 import subprocess 24 import subprocess
23 import sys 25 import sys
24 import time 26 import time
27 import threading
28 import traceback
25 import xml.dom.minidom 29 import xml.dom.minidom
26 import xml.parsers.expat 30 import xml.parsers.expat
27 31
28 32
29 class CheckCallError(OSError): 33 class CheckCallError(OSError):
30 """CheckCall() returned non-0.""" 34 """CheckCall() returned non-0."""
31 def __init__(self, command, cwd, retcode, stdout, stderr=None): 35 def __init__(self, command, cwd, retcode, stdout, stderr=None):
32 OSError.__init__(self, command, cwd, retcode, stdout, stderr) 36 OSError.__init__(self, command, cwd, retcode, stdout, stderr)
33 self.command = command 37 self.command = command
34 self.cwd = cwd 38 self.cwd = cwd
(...skipping 329 matching lines...) Expand 10 before | Expand all | Expand 10 after
364 config_path = FindFileUpwards(config_file, path) 368 config_path = FindFileUpwards(config_file, path)
365 369
366 if not config_path: 370 if not config_path:
367 print "Can't find %s" % config_file 371 print "Can't find %s" % config_file
368 return None 372 return None
369 373
370 env = {} 374 env = {}
371 execfile(config_path, env) 375 execfile(config_path, env)
372 config_dir = os.path.dirname(config_path) 376 config_dir = os.path.dirname(config_path)
373 return config_dir, env['entries'] 377 return config_dir, env['entries']
378
379
380 class ThreadPool:
381 """A thread pool class that lets one schedule jobs on many worker threads."""
382
383 def __init__(self, threads=1):
384 self._threads = threads
385 self._queue = Queue.Queue()
386 self._jobs_left = 0
387 self._condition = threading.Condition()
388 self._workers = []
389
390 class Worker(threading.Thread):
391 """Internal worker class that executes jobs from the ThreadPool queue."""
392
393 def __init__(self, pool):
394 threading.Thread.__init__(self)
395 self.setDaemon(True)
396 self._pool = pool
397 self._done = False
398 self.exceptions = []
399
400 def Done(self):
401 """Terminates the worker threads."""
402 self._done = True
403
404 def run(self):
405 """Executes jobs from the pool's queue."""
406 while not self._done:
407 f = self._pool._queue.get()
408 try:
409 try:
410 f(self)
411 except Exception, e:
412 # Catch all exceptions, otherwise we can't join the thread. Print
413 # the backtrace now, but keep the exception so that we can raise it
414 # on the main thread.
415 type, value, tb = sys.exc_info()
416 traceback.print_exception(type, value, tb)
417 self.exceptions.append(e)
418 finally:
419 self._pool._JobDone()
420
421 def _AddJobToQueue(self, job):
422 self._condition.acquire()
423 self._queue.put(job)
424 self._jobs_left += 1
425 self._condition.release()
426
427 def _JobDone(self):
428 self._condition.acquire()
429 try:
430 assert self._jobs_left
431 self._jobs_left -= 1
432 if self._jobs_left == 0:
433 self._condition.notify()
434 finally:
435 self._condition.release()
436
437 def _JoinQueue(self):
438 self._condition.acquire()
439 try:
440 while self._jobs_left:
441 self._condition.wait(1)
442 finally:
443 self._condition.release()
444
445 def Start(self):
446 """Starts the thread pool. Spawns worker threads."""
447 if not self._threads:
448 return
449 assert not self._workers
450 for i in xrange(0, self._threads):
451 worker = self.Worker(self)
452 self._workers.append(worker)
453 worker.start()
454
455 def Stop(self):
456 """Stops the thread pool. Joins all worker threads."""
457 if not self._threads:
458 return
459 assert self._workers
460 for i in xrange(0, len(self._workers)):
461 wrapped = lambda thread: thread.Done()
462 self._AddJobToQueue(wrapped)
463 self._JoinQueue()
464 for worker in self._workers:
465 while True:
466 worker.join(1)
467 if not worker.isAlive():
468 break
469 try:
470 for worker in self._workers:
471 for e in worker.exceptions:
472 # If we collected exceptions, raise them now.
473 raise e
474 finally:
475 self._workers = []
476
477 def AddJob(self, function):
478 """Adds a job to the queue.
479
480 A job is a simple closure, that will get executed on one of the worker
481 threads."""
482 if self._threads:
483 wrapped = lambda worker: function()
484 self._AddJobToQueue(wrapped)
485 else:
486 function()
487
488 def WaitJobs(self):
489 """Waits for all jobs to be completed."""
490 if not self._threads:
491 return
492 assert self._workers
493 self._JoinQueue()
494
495
496 class ThreadSafeProgress(Progress):
497 """A thread safe progress meter.
498
499 This class just wraps around a Progress class, that just forwards calls while
500 holding a lock."""
501 def __init__(self, title, total=0):
502 Progress.__init__(self, title, total)
503 self._lock = threading.Lock()
504
505 def update(self, inc=1):
506 self._lock.acquire()
507 Progress.update(self, inc)
508 self._lock.release()
509
510 def end(self):
511 self._lock.acquire()
512 Progress.end(self)
513 self._lock.release()
OLDNEW
« no previous file with comments | « gclient.py ('k') | tests/gclient_utils_test.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698