| 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): |
| (...skipping 11 matching lines...) Expand all Loading... |
| 22 import signal | 22 import signal |
| 23 import sys | 23 import sys |
| 24 import tempfile | 24 import tempfile |
| 25 import threading | 25 import threading |
| 26 | 26 |
| 27 import subprocess2 | 27 import subprocess2 |
| 28 | 28 |
| 29 | 29 |
| 30 GIT_EXE = 'git.bat' if sys.platform.startswith('win') else 'git' | 30 GIT_EXE = 'git.bat' if sys.platform.startswith('win') else 'git' |
| 31 | 31 |
| 32 NO_BRANCH = ('* (no branch)', '* (detached from ') |
| 33 |
| 32 | 34 |
| 33 class BadCommitRefException(Exception): | 35 class BadCommitRefException(Exception): |
| 34 def __init__(self, refs): | 36 def __init__(self, refs): |
| 35 msg = ('one of %s does not seem to be a valid commitref.' % | 37 msg = ('one of %s does not seem to be a valid commitref.' % |
| 36 str(refs)) | 38 str(refs)) |
| 37 super(BadCommitRefException, self).__init__(msg) | 39 super(BadCommitRefException, self).__init__(msg) |
| 38 | 40 |
| 39 | 41 |
| 40 def memoize_one(**kwargs): | 42 def memoize_one(**kwargs): |
| 41 """Memoizes a single-argument pure function. | 43 """Memoizes a single-argument pure function. |
| (...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 192 return self.inc | 194 return self.inc |
| 193 | 195 |
| 194 def __exit__(self, _exc_type, _exc_value, _traceback): | 196 def __exit__(self, _exc_type, _exc_value, _traceback): |
| 195 self._dead = True | 197 self._dead = True |
| 196 with self._dead_cond: | 198 with self._dead_cond: |
| 197 self._dead_cond.notifyAll() | 199 self._dead_cond.notifyAll() |
| 198 self._thread.join() | 200 self._thread.join() |
| 199 del self._thread | 201 del self._thread |
| 200 | 202 |
| 201 | 203 |
| 204 def abbrev(ref): |
| 205 return run('rev-parse', '--abbrev-ref', ref) |
| 206 |
| 207 |
| 208 def branches(*args): |
| 209 for line in run('branch', *args).splitlines(): |
| 210 if line.startswith(NO_BRANCH): |
| 211 continue |
| 212 yield line.split()[-1] |
| 213 |
| 214 |
| 215 def config_list(option): |
| 216 try: |
| 217 return run('config', '--get-all', option).split() |
| 218 except subprocess2.CalledProcessError: |
| 219 return [] |
| 220 |
| 221 |
| 222 def current_branch(): |
| 223 return abbrev('HEAD') |
| 224 |
| 225 |
| 202 def parse_commitrefs(*commitrefs): | 226 def parse_commitrefs(*commitrefs): |
| 203 """Returns binary encoded commit hashes for one or more commitrefs. | 227 """Returns binary encoded commit hashes for one or more commitrefs. |
| 204 | 228 |
| 205 A commitref is anything which can resolve to a commit. Popular examples: | 229 A commitref is anything which can resolve to a commit. Popular examples: |
| 206 * 'HEAD' | 230 * 'HEAD' |
| 207 * 'origin/master' | 231 * 'origin/master' |
| 208 * 'cool_branch~2' | 232 * 'cool_branch~2' |
| 209 """ | 233 """ |
| 210 try: | 234 try: |
| 211 return map(binascii.unhexlify, hashes(*commitrefs)) | 235 return map(binascii.unhexlify, hash_multi(*commitrefs)) |
| 212 except subprocess2.CalledProcessError: | 236 except subprocess2.CalledProcessError: |
| 213 raise BadCommitRefException(commitrefs) | 237 raise BadCommitRefException(commitrefs) |
| 214 | 238 |
| 215 | 239 |
| 216 def run(*cmd, **kwargs): | 240 def run(*cmd, **kwargs): |
| 217 """Runs a git command. Returns stdout as a string. | 241 """Runs a git command. Returns stdout as a string. |
| 218 | 242 |
| 219 If logging is DEBUG, we'll print the command before we run it. | 243 If logging is DEBUG, we'll print the command before we run it. |
| 220 | 244 |
| 221 kwargs | 245 kwargs |
| 222 autostrip (bool) - Strip the output. Defaults to True. | 246 autostrip (bool) - Strip the output. Defaults to True. |
| 223 Output string is always strip()'d. | 247 Output string is always strip()'d. |
| 224 """ | 248 """ |
| 225 autostrip = kwargs.pop('autostrip', True) | 249 autostrip = kwargs.pop('autostrip', True) |
| 226 cmd = (GIT_EXE,) + cmd | 250 cmd = (GIT_EXE,) + cmd |
| 227 logging.debug('Running %s', ' '.join(repr(tok) for tok in cmd)) | 251 logging.debug('Running %s', ' '.join(repr(tok) for tok in cmd)) |
| 228 ret = subprocess2.check_output(cmd, stderr=subprocess2.PIPE, **kwargs) | 252 ret = subprocess2.check_output(cmd, stderr=subprocess2.PIPE, **kwargs) |
| 229 if autostrip: | 253 if autostrip: |
| 230 ret = (ret or '').strip() | 254 ret = (ret or '').strip() |
| 231 return ret | 255 return ret |
| 232 | 256 |
| 233 | 257 |
| 234 def hashes(*reflike): | 258 def hash_one(reflike): |
| 259 return run('rev-parse', reflike) |
| 260 |
| 261 |
| 262 def hash_multi(*reflike): |
| 235 return run('rev-parse', *reflike).splitlines() | 263 return run('rev-parse', *reflike).splitlines() |
| 236 | 264 |
| 237 | 265 |
| 238 def intern_f(f, kind='blob'): | 266 def intern_f(f, kind='blob'): |
| 239 """Interns a file object into the git object store. | 267 """Interns a file object into the git object store. |
| 240 | 268 |
| 241 Args: | 269 Args: |
| 242 f (file-like object) - The file-like object to intern | 270 f (file-like object) - The file-like object to intern |
| 243 kind (git object type) - One of 'blob', 'commit', 'tree', 'tag'. | 271 kind (git object type) - One of 'blob', 'commit', 'tree', 'tag'. |
| 244 | 272 |
| 245 Returns the git hash of the interned object (hex encoded). | 273 Returns the git hash of the interned object (hex encoded). |
| 246 """ | 274 """ |
| 247 ret = run('hash-object', '-t', kind, '-w', '--stdin', stdin=f) | 275 ret = run('hash-object', '-t', kind, '-w', '--stdin', stdin=f) |
| 248 f.close() | 276 f.close() |
| 249 return ret | 277 return ret |
| 250 | 278 |
| 251 | 279 |
| 280 def tags(*args): |
| 281 for line in run('tag', *args).splitlines(): |
| 282 if line.startswith(NO_BRANCH): |
| 283 continue |
| 284 yield line.split()[-1] |
| 285 |
| 286 |
| 252 def tree(treeref, recurse=False): | 287 def tree(treeref, recurse=False): |
| 253 """Returns a dict representation of a git tree object. | 288 """Returns a dict representation of a git tree object. |
| 254 | 289 |
| 255 Args: | 290 Args: |
| 256 treeref (str) - a git ref which resolves to a tree (commits count as trees). | 291 treeref (str) - a git ref which resolves to a tree (commits count as trees). |
| 257 recurse (bool) - include all of the tree's decendants too. File names will | 292 recurse (bool) - include all of the tree's decendants too. File names will |
| 258 take the form of 'some/path/to/file'. | 293 take the form of 'some/path/to/file'. |
| 259 | 294 |
| 260 Return format: | 295 Return format: |
| 261 { 'file_name': (mode, type, ref) } | 296 { 'file_name': (mode, type, ref) } |
| (...skipping 17 matching lines...) Expand all Loading... |
| 279 opts.append(treeref) | 314 opts.append(treeref) |
| 280 try: | 315 try: |
| 281 for line in run(*opts).splitlines(): | 316 for line in run(*opts).splitlines(): |
| 282 mode, typ, ref, name = line.split(None, 3) | 317 mode, typ, ref, name = line.split(None, 3) |
| 283 ret[name] = (mode, typ, ref) | 318 ret[name] = (mode, typ, ref) |
| 284 except subprocess2.CalledProcessError: | 319 except subprocess2.CalledProcessError: |
| 285 return None | 320 return None |
| 286 return ret | 321 return ret |
| 287 | 322 |
| 288 | 323 |
| 324 def upstream(branch): |
| 325 try: |
| 326 return run('rev-parse', '--abbrev-ref', '--symbolic-full-name', |
| 327 branch+'@{upstream}') |
| 328 except subprocess2.CalledProcessError: |
| 329 return None |
| 330 |
| 331 |
| 289 def mktree(treedict): | 332 def mktree(treedict): |
| 290 """Makes a git tree object and returns its hash. | 333 """Makes a git tree object and returns its hash. |
| 291 | 334 |
| 292 See |tree()| for the values of mode, type, and ref. | 335 See |tree()| for the values of mode, type, and ref. |
| 293 | 336 |
| 294 Args: | 337 Args: |
| 295 treedict - { name: (mode, type, ref) } | 338 treedict - { name: (mode, type, ref) } |
| 296 """ | 339 """ |
| 297 with tempfile.TemporaryFile() as f: | 340 with tempfile.TemporaryFile() as f: |
| 298 for name, (mode, typ, ref) in treedict.iteritems(): | 341 for name, (mode, typ, ref) in treedict.iteritems(): |
| 299 f.write('%s %s %s\t%s\0' % (mode, typ, ref, name)) | 342 f.write('%s %s %s\t%s\0' % (mode, typ, ref, name)) |
| 300 f.seek(0) | 343 f.seek(0) |
| 301 return run('mktree', '-z', stdin=f) | 344 return run('mktree', '-z', stdin=f) |
| OLD | NEW |