| 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 14 matching lines...) Expand all Loading... |
| 25 import setup_color | 25 import setup_color |
| 26 import shutil | 26 import shutil |
| 27 import signal | 27 import signal |
| 28 import sys | 28 import sys |
| 29 import tempfile | 29 import tempfile |
| 30 import textwrap | 30 import textwrap |
| 31 import threading | 31 import threading |
| 32 | 32 |
| 33 import subprocess2 | 33 import subprocess2 |
| 34 | 34 |
| 35 from StringIO import StringIO |
| 36 |
| 37 |
| 35 ROOT = os.path.abspath(os.path.dirname(__file__)) | 38 ROOT = os.path.abspath(os.path.dirname(__file__)) |
| 36 | |
| 37 IS_WIN = sys.platform == 'win32' | 39 IS_WIN = sys.platform == 'win32' |
| 38 GIT_EXE = ROOT+'\\git.bat' if IS_WIN else 'git' | 40 GIT_EXE = ROOT+'\\git.bat' if IS_WIN else 'git' |
| 39 TEST_MODE = False | 41 TEST_MODE = False |
| 40 | 42 |
| 41 FREEZE = 'FREEZE' | 43 FREEZE = 'FREEZE' |
| 42 FREEZE_SECTIONS = { | 44 FREEZE_SECTIONS = { |
| 43 'indexed': 'soft', | 45 'indexed': 'soft', |
| 44 'unindexed': 'mixed' | 46 'unindexed': 'mixed' |
| 45 } | 47 } |
| 46 FREEZE_MATCHER = re.compile(r'%s.(%s)' % (FREEZE, '|'.join(FREEZE_SECTIONS))) | 48 FREEZE_MATCHER = re.compile(r'%s.(%s)' % (FREEZE, '|'.join(FREEZE_SECTIONS))) |
| (...skipping 338 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 385 except subprocess2.CalledProcessError: | 387 except subprocess2.CalledProcessError: |
| 386 pass | 388 pass |
| 387 | 389 |
| 388 | 390 |
| 389 def diff(oldrev, newrev, *args): | 391 def diff(oldrev, newrev, *args): |
| 390 return run('diff', oldrev, newrev, *args) | 392 return run('diff', oldrev, newrev, *args) |
| 391 | 393 |
| 392 | 394 |
| 393 def freeze(): | 395 def freeze(): |
| 394 took_action = False | 396 took_action = False |
| 397 key = 'depot-tools.freeze-size-limit' |
| 398 MB = 2**20 |
| 399 limit_mb = get_config_int(key, 100) |
| 400 untracked_bytes = 0 |
| 401 |
| 402 for f, s in status(): |
| 403 if is_unmerged(s): |
| 404 die("Cannot freeze unmerged changes!") |
| 405 if limit_mb > 0: |
| 406 if s.lstat == '?': |
| 407 untracked_bytes += os.stat(f).st_size |
| 408 if untracked_bytes > limit_mb * MB: |
| 409 die("""\ |
| 410 You appear to have too much untracked+unignored data in your git |
| 411 checkout: %.1f / %d MB. |
| 412 |
| 413 Run `git status` to see what it is. |
| 414 |
| 415 In addition to making many git commands slower, this will prevent |
| 416 depot_tools from freezing your in-progress changes. |
| 417 |
| 418 You should add untracked data that you want to ignore to your repo's |
| 419 .git/info/excludes |
| 420 file. See `git help ignore` for the format of this file. |
| 421 |
| 422 If this data is indended as part of your commit, you may adjust the |
| 423 freeze limit by running: |
| 424 git config %s <new_limit> |
| 425 Where <new_limit> is an integer threshold in megabytes.""", |
| 426 untracked_bytes / (MB * 1.0), limit_mb, key) |
| 395 | 427 |
| 396 try: | 428 try: |
| 397 run('commit', '--no-verify', '-m', FREEZE + '.indexed') | 429 run('commit', '--no-verify', '-m', FREEZE + '.indexed') |
| 398 took_action = True | 430 took_action = True |
| 399 except subprocess2.CalledProcessError: | 431 except subprocess2.CalledProcessError: |
| 400 pass | 432 pass |
| 401 | 433 |
| 402 try: | 434 try: |
| 403 run('add', '-A') | 435 run('add', '-A') |
| 404 run('commit', '--no-verify', '-m', FREEZE + '.unindexed') | 436 run('commit', '--no-verify', '-m', FREEZE + '.unindexed') |
| (...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 495 ret = run('hash-object', '-t', kind, '-w', '--stdin', stdin=f) | 527 ret = run('hash-object', '-t', kind, '-w', '--stdin', stdin=f) |
| 496 f.close() | 528 f.close() |
| 497 return ret | 529 return ret |
| 498 | 530 |
| 499 | 531 |
| 500 def is_dormant(branch): | 532 def is_dormant(branch): |
| 501 # TODO(iannucci): Do an oldness check? | 533 # TODO(iannucci): Do an oldness check? |
| 502 return branch_config(branch, 'dormant', 'false') != 'false' | 534 return branch_config(branch, 'dormant', 'false') != 'false' |
| 503 | 535 |
| 504 | 536 |
| 537 def is_unmerged(stat_value): |
| 538 return ( |
| 539 'U' in (stat_value.lstat, stat_value.rstat) or |
| 540 ((stat_value.lstat == stat_value.rstat) and stat_value.lstat in 'AD') |
| 541 ) |
| 542 |
| 543 |
| 505 def manual_merge_base(branch, base, parent): | 544 def manual_merge_base(branch, base, parent): |
| 506 set_branch_config(branch, 'base', base) | 545 set_branch_config(branch, 'base', base) |
| 507 set_branch_config(branch, 'base-upstream', parent) | 546 set_branch_config(branch, 'base-upstream', parent) |
| 508 | 547 |
| 509 | 548 |
| 510 def mktree(treedict): | 549 def mktree(treedict): |
| 511 """Makes a git tree object and returns its hash. | 550 """Makes a git tree object and returns its hash. |
| 512 | 551 |
| 513 See |tree()| for the values of mode, type, and ref. | 552 See |tree()| for the values of mode, type, and ref. |
| 514 | 553 |
| (...skipping 189 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 704 if dirty: | 743 if dirty: |
| 705 print 'Cannot %s with a dirty tree. You must commit locally first.' % cmd | 744 print 'Cannot %s with a dirty tree. You must commit locally first.' % cmd |
| 706 print 'Uncommitted files: (git diff-index --name-status HEAD)' | 745 print 'Uncommitted files: (git diff-index --name-status HEAD)' |
| 707 print dirty[:4096] | 746 print dirty[:4096] |
| 708 if len(dirty) > 4096: # pragma: no cover | 747 if len(dirty) > 4096: # pragma: no cover |
| 709 print '... (run "git diff-index --name-status HEAD" to see full output).' | 748 print '... (run "git diff-index --name-status HEAD" to see full output).' |
| 710 return True | 749 return True |
| 711 return False | 750 return False |
| 712 | 751 |
| 713 | 752 |
| 753 def status(): |
| 754 """Returns a parsed version of git-status. |
| 755 |
| 756 Returns a generator of (current_name, (lstat, rstat, src)) pairs where: |
| 757 * current_name is the name of the file |
| 758 * lstat is the left status code letter from git-status |
| 759 * rstat is the left status code letter from git-status |
| 760 * src is the current name of the file, or the original name of the file |
| 761 if lstat == 'R' |
| 762 """ |
| 763 stat_entry = collections.namedtuple('stat_entry', 'lstat rstat src') |
| 764 |
| 765 def tokenizer(stream): |
| 766 acc = StringIO() |
| 767 c = None |
| 768 while c != '': |
| 769 c = stream.read(1) |
| 770 if c in (None, '', '\0'): |
| 771 if acc.len: |
| 772 yield acc.getvalue() |
| 773 acc = StringIO() |
| 774 else: |
| 775 acc.write(c) |
| 776 |
| 777 def parser(tokens): |
| 778 while True: |
| 779 # Raises StopIteration if it runs out of tokens. |
| 780 status_dest = next(tokens) |
| 781 stat, dest = status_dest[:2], status_dest[3:] |
| 782 lstat, rstat = stat |
| 783 if lstat == 'R': |
| 784 src = next(tokens) |
| 785 else: |
| 786 src = dest |
| 787 yield (dest, stat_entry(lstat, rstat, src)) |
| 788 |
| 789 return parser(tokenizer(run_stream('status', '-z', bufsize=-1))) |
| 790 |
| 791 |
| 714 def squash_current_branch(header=None, merge_base=None): | 792 def squash_current_branch(header=None, merge_base=None): |
| 715 header = header or 'git squash commit.' | 793 header = header or 'git squash commit.' |
| 716 merge_base = merge_base or get_or_create_merge_base(current_branch()) | 794 merge_base = merge_base or get_or_create_merge_base(current_branch()) |
| 717 log_msg = header + '\n' | 795 log_msg = header + '\n' |
| 718 if log_msg: | 796 if log_msg: |
| 719 log_msg += '\n' | 797 log_msg += '\n' |
| 720 log_msg += run('log', '--reverse', '--format=%H%n%B', '%s..HEAD' % merge_base) | 798 log_msg += run('log', '--reverse', '--format=%H%n%B', '%s..HEAD' % merge_base) |
| 721 run('reset', '--soft', merge_base) | 799 run('reset', '--soft', merge_base) |
| 722 | 800 |
| 723 if not get_dirty_files(): | 801 if not get_dirty_files(): |
| (...skipping 191 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 915 ['HEAD']) | 993 ['HEAD']) |
| 916 | 994 |
| 917 | 995 |
| 918 def clone_file(repository, new_workdir, link, operation): | 996 def clone_file(repository, new_workdir, link, operation): |
| 919 if not os.path.exists(os.path.join(repository, link)): | 997 if not os.path.exists(os.path.join(repository, link)): |
| 920 return | 998 return |
| 921 link_dir = os.path.dirname(os.path.join(new_workdir, link)) | 999 link_dir = os.path.dirname(os.path.join(new_workdir, link)) |
| 922 if not os.path.exists(link_dir): | 1000 if not os.path.exists(link_dir): |
| 923 os.makedirs(link_dir) | 1001 os.makedirs(link_dir) |
| 924 operation(os.path.join(repository, link), os.path.join(new_workdir, link)) | 1002 operation(os.path.join(repository, link), os.path.join(new_workdir, link)) |
| OLD | NEW |