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