Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(243)

Side by Side Diff: git_common.py

Issue 2052113002: Make git-freeze bail out if the user has too much untracked data. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/tools/depot_tools
Patch Set: Final comment Created 4 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | man/html/git-freeze.html » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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))
OLDNEW
« no previous file with comments | « no previous file | man/html/git-freeze.html » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698