Chromium Code Reviews| 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 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 MERGE_BASE_TAG_FMT = "gitscripts.merge_base_for_%s" | |
|
agable
2014/02/28 20:14:16
Ugly that some of these are using a gitscripts con
| |
| 31 | |
| 32 | |
| 30 class DEFAULT(object): | 33 class DEFAULT(object): |
| 31 def __init__(self, constructor): | 34 def __init__(self, constructor): |
| 32 self.constructor = constructor | 35 self.constructor = constructor |
| 33 | 36 |
| 34 @staticmethod | 37 @staticmethod |
| 35 def get_from(inst_or_obj): | 38 def get_from(inst_or_obj): |
| 36 if isinstance(inst_or_obj, DEFAULT): | 39 if isinstance(inst_or_obj, DEFAULT): |
| 37 return inst_or_obj.constructor() | 40 return inst_or_obj.constructor() |
| 38 else: | 41 else: |
| 39 return inst_or_obj | 42 return inst_or_obj |
| (...skipping 177 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 217 return run('rev-parse', '--abbrev-ref', ref) | 220 return run('rev-parse', '--abbrev-ref', ref) |
| 218 | 221 |
| 219 | 222 |
| 220 def branches(*args): | 223 def branches(*args): |
| 221 for line in run('branch', *args).splitlines(): | 224 for line in run('branch', *args).splitlines(): |
| 222 if line.startswith(NO_BRANCH): | 225 if line.startswith(NO_BRANCH): |
| 223 continue | 226 continue |
| 224 yield line.split()[-1] | 227 yield line.split()[-1] |
| 225 | 228 |
| 226 | 229 |
| 230 def clean_refs(): | |
|
agable
2014/02/28 20:14:16
This is really only cleaning tags, not refs...
| |
| 231 run('tag', '-d', | |
| 232 *[t.strip() for t in run('tag', '-l', 'gitscripts.*').split()]) | |
| 233 | |
| 234 | |
| 227 def config_list(option, default=DEFAULT(list)): | 235 def config_list(option, default=DEFAULT(list)): |
| 228 try: | 236 try: |
| 229 return run('config', '--get-all', option).split() | 237 return run('config', '--get-all', option).split() |
| 230 except subprocess2.CalledProcessError: | 238 except subprocess2.CalledProcessError: |
| 231 return DEFAULT.get_from(default) | 239 return DEFAULT.get_from(default) |
| 232 | 240 |
| 233 | 241 |
| 234 def current_branch(): | 242 def current_branch(): |
| 235 return abbrev('HEAD') | 243 return abbrev('HEAD') |
| 236 | 244 |
| 237 | 245 |
| 238 def parse_commitrefs(*commitrefs): | 246 def parse_commitrefs(*commitrefs): |
| 239 """Returns binary encoded commit hashes for one or more commitrefs. | 247 """Returns binary encoded commit hashes for one or more commitrefs. |
| 240 | 248 |
| 241 A commitref is anything which can resolve to a commit. Popular examples: | 249 A commitref is anything which can resolve to a commit. Popular examples: |
| 242 * 'HEAD' | 250 * 'HEAD' |
| 243 * 'origin/master' | 251 * 'origin/master' |
| 244 * 'cool_branch~2' | 252 * 'cool_branch~2' |
| 245 """ | 253 """ |
| 246 try: | 254 try: |
| 247 return map(binascii.unhexlify, hash_multi(*commitrefs)) | 255 return map(binascii.unhexlify, hash_multi(*commitrefs)) |
| 248 except subprocess2.CalledProcessError: | 256 except subprocess2.CalledProcessError: |
| 249 raise BadCommitRefException(commitrefs) | 257 raise BadCommitRefException(commitrefs) |
| 250 | 258 |
| 251 | 259 |
| 260 def root(): | |
| 261 return run('config', 'depot_tools.upstream') or 'origin/master' | |
| 262 | |
| 263 | |
| 252 def run(*cmd, **kwargs): | 264 def run(*cmd, **kwargs): |
| 253 """Runs a git command. Returns stdout as a string. | 265 """Runs a git command. Returns stdout as a string. |
| 254 | 266 |
| 255 If logging is DEBUG, we'll print the command before we run it. | 267 If logging is DEBUG, we'll print the command before we run it. |
| 256 | 268 |
| 257 kwargs | 269 kwargs |
| 258 autostrip (bool) - Strip the output. Defaults to True. | 270 autostrip (bool) - Strip the output. Defaults to True. |
| 259 """ | 271 """ |
| 260 autostrip = kwargs.pop('autostrip', True) | 272 autostrip = kwargs.pop('autostrip', True) |
| 261 ret = stream(*cmd, **kwargs).read() | 273 ret = stream(*cmd, **kwargs).read() |
| 262 if autostrip: | 274 if autostrip: |
| 263 ret = (ret or '').strip() | 275 ret = (ret or '').strip() |
| 264 return ret | 276 return ret |
| 265 | 277 |
| 266 | 278 |
| 267 def stream(*cmd, **kwargs): | 279 def stream(*cmd, **kwargs): |
| 268 """Runs a git command. Returns stdout as a file. | 280 """Runs a git command. Returns stdout as a file. |
| 269 | 281 |
| 270 If logging is DEBUG, we'll print the command before we run it. | 282 If logging is DEBUG, we'll print the command before we run it. |
| 271 """ | 283 """ |
| 272 cmd = (GIT_EXE,) + cmd | 284 cmd = (GIT_EXE,) + cmd |
| 273 logging.debug('Running %s', ' '.join(repr(tok) for tok in cmd)) | 285 logging.debug('Running %s', ' '.join(repr(tok) for tok in cmd)) |
| 274 proc = subprocess2.Popen(cmd, stderr=subprocess2.VOID, | 286 proc = subprocess2.Popen(cmd, stderr=subprocess2.VOID, |
| 275 stdout=subprocess2.PIPE, **kwargs) | 287 stdout=subprocess2.PIPE, **kwargs) |
| 276 return proc.stdout | 288 return proc.stdout |
| 277 | 289 |
| 278 | 290 |
| 291 def get_or_create_merge_base_tag(branch, parent): | |
| 292 tag = MERGE_BASE_TAG_FMT % hash_one(branch) | |
| 293 tagval = None | |
| 294 try: | |
| 295 tagval = hash_one(tag) | |
| 296 logging.debug('Found tagged merge-base for %s: %s', branch, tagval) | |
| 297 except subprocess2.CalledProcessError: | |
| 298 pass | |
| 299 if not tagval: | |
| 300 run('tag', '-m', tag, tag, run('merge-base', parent, branch)) | |
| 301 tagval = hash_one(tag) | |
| 302 return tagval+'^{}' # this lets rev-parse know this is actually a tag | |
| 303 | |
| 304 | |
| 279 def hash_one(reflike): | 305 def hash_one(reflike): |
| 280 return run('rev-parse', reflike) | 306 return run('rev-parse', reflike) |
| 281 | 307 |
| 282 | 308 |
| 283 def hash_multi(*reflike): | 309 def hash_multi(*reflike): |
| 284 return run('rev-parse', *reflike).splitlines() | 310 return run('rev-parse', *reflike).splitlines() |
| 285 | 311 |
| 286 | 312 |
| 287 def intern_f(f, kind='blob'): | 313 def intern_f(f, kind='blob'): |
| 288 """Interns a file object into the git object store. | 314 """Interns a file object into the git object store. |
| 289 | 315 |
| 290 Args: | 316 Args: |
| 291 f (file-like object) - The file-like object to intern | 317 f (file-like object) - The file-like object to intern |
| 292 kind (git object type) - One of 'blob', 'commit', 'tree', 'tag'. | 318 kind (git object type) - One of 'blob', 'commit', 'tree', 'tag'. |
| 293 | 319 |
| 294 Returns the git hash of the interned object (hex encoded). | 320 Returns the git hash of the interned object (hex encoded). |
| 295 """ | 321 """ |
| 296 ret = run('hash-object', '-t', kind, '-w', '--stdin', stdin=f) | 322 ret = run('hash-object', '-t', kind, '-w', '--stdin', stdin=f) |
| 297 f.close() | 323 f.close() |
| 298 return ret | 324 return ret |
| 299 | 325 |
| 300 | 326 |
| 327 def manual_merge_base_tag(branch, base): | |
| 328 tag = MERGE_BASE_TAG_FMT % hash_one(branch) | |
| 329 run('tag', '-f', '-m', tag, tag, hash_one(base)) | |
| 330 | |
| 331 | |
| 332 def nuke_merge_base_tag(branch): | |
|
agable
2014/02/28 20:14:16
s/nuke/remove/
| |
| 333 tag = MERGE_BASE_TAG_FMT % hash_one(branch) | |
| 334 run('tag', '-d', tag) | |
| 335 | |
| 336 | |
| 301 def tags(*args): | 337 def tags(*args): |
| 302 for line in run('tag', *args).splitlines(): | 338 for line in run('tag', *args).splitlines(): |
| 303 if line.startswith(NO_BRANCH): | 339 if line.startswith(NO_BRANCH): |
| 304 continue | 340 continue |
| 305 yield line.split()[-1] | 341 yield line.split()[-1] |
| 306 | 342 |
| 307 | 343 |
| 308 def tree(treeref, recurse=False): | 344 def tree(treeref, recurse=False): |
| 309 """Returns a dict representation of a git tree object. | 345 """Returns a dict representation of a git tree object. |
| 310 | 346 |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 356 See |tree()| for the values of mode, type, and ref. | 392 See |tree()| for the values of mode, type, and ref. |
| 357 | 393 |
| 358 Args: | 394 Args: |
| 359 treedict - { name: (mode, type, ref) } | 395 treedict - { name: (mode, type, ref) } |
| 360 """ | 396 """ |
| 361 with tempfile.TemporaryFile() as f: | 397 with tempfile.TemporaryFile() as f: |
| 362 for name, (mode, typ, ref) in treedict.iteritems(): | 398 for name, (mode, typ, ref) in treedict.iteritems(): |
| 363 f.write('%s %s %s\t%s\0' % (mode, typ, ref, name)) | 399 f.write('%s %s %s\t%s\0' % (mode, typ, ref, name)) |
| 364 f.seek(0) | 400 f.seek(0) |
| 365 return run('mktree', '-z', stdin=f) | 401 return run('mktree', '-z', stdin=f) |
| OLD | NEW |