Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 # Copyright 2014 The Chromium Authors. All rights reserved. | 1 # Copyright 2014 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 263 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 274 how many times the decorated |function| is called.""" | 274 how many times the decorated |function| is called.""" |
| 275 def _inner_gen(): | 275 def _inner_gen(): |
| 276 yield function() | 276 yield function() |
| 277 while True: | 277 while True: |
| 278 yield | 278 yield |
| 279 return _inner_gen().next | 279 return _inner_gen().next |
| 280 | 280 |
| 281 | 281 |
| 282 ## Git functions | 282 ## Git functions |
| 283 | 283 |
| 284 def die(message, *args): | |
| 285 print >> sys.stderr, textwrap.dedent(message % args) | |
| 286 sys.exit(1) | |
| 287 | |
| 284 | 288 |
| 285 def blame(filename, revision=None, porcelain=False, *_args): | 289 def blame(filename, revision=None, porcelain=False, *_args): |
| 286 command = ['blame'] | 290 command = ['blame'] |
| 287 if porcelain: | 291 if porcelain: |
| 288 command.append('-p') | 292 command.append('-p') |
| 289 if revision is not None: | 293 if revision is not None: |
| 290 command.append(revision) | 294 command.append(revision) |
| 291 command.extend(['--', filename]) | 295 command.extend(['--', filename]) |
| 292 return run(*command) | 296 return run(*command) |
| 293 | 297 |
| 294 | 298 |
| 295 def branch_config(branch, option, default=None): | 299 def branch_config(branch, option, default=None): |
| 296 return config('branch.%s.%s' % (branch, option), default=default) | 300 return get_config('branch.%s.%s' % (branch, option), default=default) |
| 297 | |
| 298 | |
| 299 def config_regexp(pattern): | |
| 300 if IS_WIN: # pragma: no cover | |
| 301 # this madness is because we call git.bat which calls git.exe which calls | |
| 302 # bash.exe (or something to that effect). Each layer divides the number of | |
| 303 # ^'s by 2. | |
| 304 pattern = pattern.replace('^', '^' * 8) | |
| 305 return run('config', '--get-regexp', pattern).splitlines() | |
| 306 | 301 |
| 307 | 302 |
| 308 def branch_config_map(option): | 303 def branch_config_map(option): |
| 309 """Return {branch: <|option| value>} for all branches.""" | 304 """Return {branch: <|option| value>} for all branches.""" |
| 310 try: | 305 try: |
| 311 reg = re.compile(r'^branch\.(.*)\.%s$' % option) | 306 reg = re.compile(r'^branch\.(.*)\.%s$' % option) |
| 312 lines = config_regexp(reg.pattern) | 307 lines = get_config_regexp(reg.pattern) |
| 313 return {reg.match(k).group(1): v for k, v in (l.split() for l in lines)} | 308 return {reg.match(k).group(1): v for k, v in (l.split() for l in lines)} |
| 314 except subprocess2.CalledProcessError: | 309 except subprocess2.CalledProcessError: |
| 315 return {} | 310 return {} |
| 316 | 311 |
| 317 | 312 |
| 318 def branches(*args): | 313 def branches(*args): |
| 319 NO_BRANCH = ('* (no branch', '* (detached', '* (HEAD detached') | 314 NO_BRANCH = ('* (no branch', '* (detached', '* (HEAD detached') |
| 320 | 315 |
| 321 key = 'depot-tools.branch-limit' | 316 key = 'depot-tools.branch-limit' |
| 322 limit = 20 | 317 limit = get_config_int(key, 20) |
| 323 try: | |
| 324 limit = int(config(key, limit)) | |
| 325 except ValueError: | |
| 326 pass | |
| 327 | 318 |
| 328 raw_branches = run('branch', *args).splitlines() | 319 raw_branches = run('branch', *args).splitlines() |
| 329 | 320 |
| 330 num = len(raw_branches) | 321 num = len(raw_branches) |
| 322 | |
| 331 if num > limit: | 323 if num > limit: |
| 332 print >> sys.stderr, textwrap.dedent("""\ | 324 die("""\ |
| 333 Your git repo has too many branches (%d/%d) for this tool to work well. | 325 Your git repo has too many branches (%d/%d) for this tool to work well. |
|
tandrii(chromium)
2016/06/21 14:22:49
how about adding a plug for git cl archive. Say,
agable
2016/06/21 14:31:39
Good idea, done.
| |
| 334 | 326 |
| 335 You may adjust this limit by running: | 327 You may adjust this limit by running: |
| 336 git config %s <new_limit> | 328 git config %s <new_limit> |
| 337 """ % (num, limit, key)) | 329 """, num, limit, key) |
| 338 sys.exit(1) | |
| 339 | 330 |
| 340 for line in raw_branches: | 331 for line in raw_branches: |
| 341 if line.startswith(NO_BRANCH): | 332 if line.startswith(NO_BRANCH): |
| 342 continue | 333 continue |
| 343 yield line.split()[-1] | 334 yield line.split()[-1] |
| 344 | 335 |
| 345 | 336 |
| 346 def config(option, default=None): | 337 def get_config(option, default=None): |
| 347 try: | 338 try: |
| 348 return run('config', '--get', option) or default | 339 return run('config', '--get', option) or default |
| 349 except subprocess2.CalledProcessError: | 340 except subprocess2.CalledProcessError: |
| 350 return default | 341 return default |
| 351 | 342 |
| 352 | 343 |
| 353 def config_list(option): | 344 def get_config_int(option, default=0): |
| 345 assert isinstance(default, int) | |
| 346 try: | |
| 347 return int(get_config(option, default)) | |
| 348 except ValueError: | |
| 349 return default | |
| 350 | |
| 351 | |
| 352 def get_config_list(option): | |
| 354 try: | 353 try: |
| 355 return run('config', '--get-all', option).split() | 354 return run('config', '--get-all', option).split() |
| 356 except subprocess2.CalledProcessError: | 355 except subprocess2.CalledProcessError: |
| 357 return [] | 356 return [] |
| 358 | 357 |
| 359 | 358 |
| 359 def get_config_regexp(pattern): | |
| 360 if IS_WIN: # pragma: no cover | |
| 361 # this madness is because we call git.bat which calls git.exe which calls | |
| 362 # bash.exe (or something to that effect). Each layer divides the number of | |
| 363 # ^'s by 2. | |
| 364 pattern = pattern.replace('^', '^' * 8) | |
| 365 return run('config', '--get-regexp', pattern).splitlines() | |
| 366 | |
| 367 | |
| 360 def current_branch(): | 368 def current_branch(): |
| 361 try: | 369 try: |
| 362 return run('rev-parse', '--abbrev-ref', 'HEAD') | 370 return run('rev-parse', '--abbrev-ref', 'HEAD') |
| 363 except subprocess2.CalledProcessError: | 371 except subprocess2.CalledProcessError: |
| 364 return None | 372 return None |
| 365 | 373 |
| 366 | 374 |
| 367 def del_branch_config(branch, option, scope='local'): | 375 def del_branch_config(branch, option, scope='local'): |
| 368 del_config('branch.%s.%s' % (branch, option), scope=scope) | 376 del_config('branch.%s.%s' % (branch, option), scope=scope) |
| 369 | 377 |
| (...skipping 190 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 560 del_branch_config(branch, 'base') | 568 del_branch_config(branch, 'base') |
| 561 del_branch_config(branch, 'base-upstream') | 569 del_branch_config(branch, 'base-upstream') |
| 562 | 570 |
| 563 | 571 |
| 564 def repo_root(): | 572 def repo_root(): |
| 565 """Returns the absolute path to the repository root.""" | 573 """Returns the absolute path to the repository root.""" |
| 566 return run('rev-parse', '--show-toplevel') | 574 return run('rev-parse', '--show-toplevel') |
| 567 | 575 |
| 568 | 576 |
| 569 def root(): | 577 def root(): |
| 570 return config('depot-tools.upstream', 'origin/master') | 578 return get_config('depot-tools.upstream', 'origin/master') |
| 571 | 579 |
| 572 | 580 |
| 573 @contextlib.contextmanager | 581 @contextlib.contextmanager |
| 574 def less(): # pragma: no cover | 582 def less(): # pragma: no cover |
| 575 """Runs 'less' as context manager yielding its stdin as a PIPE. | 583 """Runs 'less' as context manager yielding its stdin as a PIPE. |
| 576 | 584 |
| 577 Automatically checks if sys.stdout is a non-TTY stream. If so, it avoids | 585 Automatically checks if sys.stdout is a non-TTY stream. If so, it avoids |
| 578 running less and just yields sys.stdout. | 586 running less and just yields sys.stdout. |
| 579 """ | 587 """ |
| 580 if not setup_color.IS_TTY: | 588 if not setup_color.IS_TTY: |
| (...skipping 323 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 904 ['HEAD']) | 912 ['HEAD']) |
| 905 | 913 |
| 906 | 914 |
| 907 def clone_file(repository, new_workdir, link, operation): | 915 def clone_file(repository, new_workdir, link, operation): |
| 908 if not os.path.exists(os.path.join(repository, link)): | 916 if not os.path.exists(os.path.join(repository, link)): |
| 909 return | 917 return |
| 910 link_dir = os.path.dirname(os.path.join(new_workdir, link)) | 918 link_dir = os.path.dirname(os.path.join(new_workdir, link)) |
| 911 if not os.path.exists(link_dir): | 919 if not os.path.exists(link_dir): |
| 912 os.makedirs(link_dir) | 920 os.makedirs(link_dir) |
| 913 operation(os.path.join(repository, link), os.path.join(new_workdir, link)) | 921 operation(os.path.join(repository, link), os.path.join(new_workdir, link)) |
| OLD | NEW |