OLD | NEW |
1 # Copyright 2013 The Chromium Authors. All rights reserved. | 1 # Copyright 2013 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 # Monkeypatch IMapIterator so that Ctrl-C can kill everything properly. | 5 # Monkeypatch IMapIterator so that Ctrl-C can kill everything properly. |
6 # Derived from https://gist.github.com/aljungberg/626518 | 6 # Derived from https://gist.github.com/aljungberg/626518 |
7 import multiprocessing.pool | 7 import multiprocessing.pool |
8 from multiprocessing.pool import IMapIterator | 8 from multiprocessing.pool import IMapIterator |
9 def wrapper(func): | 9 def wrapper(func): |
10 def wrap(self, timeout=None): | 10 def wrap(self, timeout=None): |
11 return func(self, timeout=timeout or 1e100) | 11 return func(self, timeout=timeout or 1e100) |
12 return wrap | 12 return wrap |
13 IMapIterator.next = wrapper(IMapIterator.next) | 13 IMapIterator.next = wrapper(IMapIterator.next) |
14 IMapIterator.__next__ = IMapIterator.next | 14 IMapIterator.__next__ = IMapIterator.next |
15 # TODO(iannucci): Monkeypatch all other 'wait' methods too. | 15 # TODO(iannucci): Monkeypatch all other 'wait' methods too. |
16 | 16 |
17 | 17 |
18 import binascii | 18 import binascii |
19 import contextlib | 19 import contextlib |
20 import functools | 20 import functools |
21 import logging | 21 import logging |
| 22 import os |
22 import signal | 23 import signal |
23 import sys | 24 import sys |
24 import tempfile | 25 import tempfile |
25 import threading | 26 import threading |
26 | 27 |
27 import subprocess2 | 28 import subprocess2 |
28 | 29 |
29 | 30 |
30 GIT_EXE = 'git.bat' if sys.platform.startswith('win') else 'git' | 31 GIT_EXE = 'git.bat' if sys.platform.startswith('win') else 'git' |
31 | 32 |
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
132 pool.close() | 133 pool.close() |
133 except: | 134 except: |
134 pool.terminate() | 135 pool.terminate() |
135 raise | 136 raise |
136 finally: | 137 finally: |
137 pool.join() | 138 pool.join() |
138 | 139 |
139 | 140 |
140 class ProgressPrinter(object): | 141 class ProgressPrinter(object): |
141 """Threaded single-stat status message printer.""" | 142 """Threaded single-stat status message printer.""" |
142 def __init__(self, fmt, enabled=None, stream=sys.stderr, period=0.5): | 143 def __init__(self, fmt, enabled=None, fout=sys.stderr, period=0.5): |
143 """Create a ProgressPrinter. | 144 """Create a ProgressPrinter. |
144 | 145 |
145 Use it as a context manager which produces a simple 'increment' method: | 146 Use it as a context manager which produces a simple 'increment' method: |
146 | 147 |
147 with ProgressPrinter('(%%(count)d/%d)' % 1000) as inc: | 148 with ProgressPrinter('(%%(count)d/%d)' % 1000) as inc: |
148 for i in xrange(1000): | 149 for i in xrange(1000): |
149 # do stuff | 150 # do stuff |
150 if i % 10 == 0: | 151 if i % 10 == 0: |
151 inc(10) | 152 inc(10) |
152 | 153 |
153 Args: | 154 Args: |
154 fmt - String format with a single '%(count)d' where the counter value | 155 fmt - String format with a single '%(count)d' where the counter value |
155 should go. | 156 should go. |
156 enabled (bool) - If this is None, will default to True if | 157 enabled (bool) - If this is None, will default to True if |
157 logging.getLogger() is set to INFO or more verbose. | 158 logging.getLogger() is set to INFO or more verbose. |
158 stream (file-like) - The stream to print status messages to. | 159 fout (file-like) - The stream to print status messages to. |
159 period (float) - The time in seconds for the printer thread to wait | 160 period (float) - The time in seconds for the printer thread to wait |
160 between printing. | 161 between printing. |
161 """ | 162 """ |
162 self.fmt = fmt | 163 self.fmt = fmt |
163 if enabled is None: # pragma: no cover | 164 if enabled is None: # pragma: no cover |
164 self.enabled = logging.getLogger().isEnabledFor(logging.INFO) | 165 self.enabled = logging.getLogger().isEnabledFor(logging.INFO) |
165 else: | 166 else: |
166 self.enabled = enabled | 167 self.enabled = enabled |
167 | 168 |
168 self._count = 0 | 169 self._count = 0 |
169 self._dead = False | 170 self._dead = False |
170 self._dead_cond = threading.Condition() | 171 self._dead_cond = threading.Condition() |
171 self._stream = stream | 172 self._stream = fout |
172 self._thread = threading.Thread(target=self._run) | 173 self._thread = threading.Thread(target=self._run) |
173 self._period = period | 174 self._period = period |
174 | 175 |
175 def _emit(self, s): | 176 def _emit(self, s): |
176 if self.enabled: | 177 if self.enabled: |
177 self._stream.write('\r' + s) | 178 self._stream.write('\r' + s) |
178 self._stream.flush() | 179 self._stream.flush() |
179 | 180 |
180 def _run(self): | 181 def _run(self): |
181 with self._dead_cond: | 182 with self._dead_cond: |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
232 raise BadCommitRefException(commitrefs) | 233 raise BadCommitRefException(commitrefs) |
233 | 234 |
234 | 235 |
235 def run(*cmd, **kwargs): | 236 def run(*cmd, **kwargs): |
236 """Runs a git command. Returns stdout as a string. | 237 """Runs a git command. Returns stdout as a string. |
237 | 238 |
238 If logging is DEBUG, we'll print the command before we run it. | 239 If logging is DEBUG, we'll print the command before we run it. |
239 | 240 |
240 kwargs | 241 kwargs |
241 autostrip (bool) - Strip the output. Defaults to True. | 242 autostrip (bool) - Strip the output. Defaults to True. |
242 Output string is always strip()'d. | |
243 """ | 243 """ |
244 autostrip = kwargs.pop('autostrip', True) | 244 autostrip = kwargs.pop('autostrip', True) |
245 cmd = (GIT_EXE,) + cmd | 245 |
246 logging.debug('Running %s', ' '.join(repr(tok) for tok in cmd)) | 246 retstream, proc = stream_proc(*cmd, **kwargs) |
247 ret = subprocess2.check_output(cmd, stderr=subprocess2.PIPE, **kwargs) | 247 ret = retstream.read() |
| 248 retcode = proc.wait() |
| 249 if retcode != 0: |
| 250 raise subprocess2.CalledProcessError(retcode, cmd, os.getcwd(), ret, None) |
| 251 |
248 if autostrip: | 252 if autostrip: |
249 ret = (ret or '').strip() | 253 ret = (ret or '').strip() |
250 return ret | 254 return ret |
251 | 255 |
252 | 256 |
| 257 def stream_proc(*cmd, **kwargs): |
| 258 """Runs a git command. Returns stdout as a file. |
| 259 |
| 260 If logging is DEBUG, we'll print the command before we run it. |
| 261 """ |
| 262 cmd = (GIT_EXE,) + cmd |
| 263 logging.debug('Running %s', ' '.join(repr(tok) for tok in cmd)) |
| 264 proc = subprocess2.Popen(cmd, stderr=subprocess2.VOID, |
| 265 stdout=subprocess2.PIPE, **kwargs) |
| 266 return proc.stdout, proc |
| 267 |
| 268 |
| 269 def stream(*cmd, **kwargs): |
| 270 return stream_proc(*cmd, **kwargs)[0] |
| 271 |
| 272 |
253 def hash_one(reflike): | 273 def hash_one(reflike): |
254 return run('rev-parse', reflike) | 274 return run('rev-parse', reflike) |
255 | 275 |
256 | 276 |
257 def hash_multi(*reflike): | 277 def hash_multi(*reflike): |
258 return run('rev-parse', *reflike).splitlines() | 278 return run('rev-parse', *reflike).splitlines() |
259 | 279 |
260 | 280 |
261 def intern_f(f, kind='blob'): | 281 def intern_f(f, kind='blob'): |
262 """Interns a file object into the git object store. | 282 """Interns a file object into the git object store. |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
327 See |tree()| for the values of mode, type, and ref. | 347 See |tree()| for the values of mode, type, and ref. |
328 | 348 |
329 Args: | 349 Args: |
330 treedict - { name: (mode, type, ref) } | 350 treedict - { name: (mode, type, ref) } |
331 """ | 351 """ |
332 with tempfile.TemporaryFile() as f: | 352 with tempfile.TemporaryFile() as f: |
333 for name, (mode, typ, ref) in treedict.iteritems(): | 353 for name, (mode, typ, ref) in treedict.iteritems(): |
334 f.write('%s %s %s\t%s\0' % (mode, typ, ref, name)) | 354 f.write('%s %s %s\t%s\0' % (mode, typ, ref, name)) |
335 f.seek(0) | 355 f.seek(0) |
336 return run('mktree', '-z', stdin=f) | 356 return run('mktree', '-z', stdin=f) |
OLD | NEW |