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

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: Address comments 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') | tests/git_common_test.py » ('J')
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 cStringIO 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 335 matching lines...) Expand 10 before | Expand all | Expand 10 after
382 except subprocess2.CalledProcessError: 384 except subprocess2.CalledProcessError:
383 pass 385 pass
384 386
385 387
386 def diff(oldrev, newrev, *args): 388 def diff(oldrev, newrev, *args):
387 return run('diff', oldrev, newrev, *args) 389 return run('diff', oldrev, newrev, *args)
388 390
389 391
390 def freeze(): 392 def freeze():
391 took_action = False 393 took_action = False
394 key = 'depot-tools.freeze-size-limit'
395 MB = 2**20
396 limit_mb = get_config_int(key, 100)
397 untracked_size = 0
398
399 for f, s in status():
400 if is_unmerged(s):
401 die("Cannot freeze unmerged changes!")
402 if limit_mb > 0:
403 if s.lstat == '?':
404 untracked_size += os.stat(f).st_size / MB
tandrii(chromium) 2016/06/21 14:43:37 don't divide here, otherwise 3 files 400KB each wi
agable 2016/06/22 11:16:51 Done
405 if untracked_size > limit_mb:
tandrii(chromium) 2016/06/21 14:43:37 divide by MB here, and better yet multiply by limi
agable 2016/06/22 11:16:51 Done
406 die("""\
407 You appear to have too much untracked+unignored data in your git
408 checkout: %d/%dMB.
tandrii(chromium) 2016/06/21 14:43:37 personal preference: s/%d/%.1f and make MB a float
agable 2016/06/22 11:16:51 Gonna leave limit in MB, since letting it be a dec
409
410 Run `git status` to see what it is.
411
412 In addition to making many git commands slower, this will prevent
413 depot_tools from freezing your in-progress changes.
414
415 You should add untracked data that you want to ignore to your repo's
416 .git/info/excludes
417 file. See `git help ignore` for the format of this file.
418
419 If this data is indended as part of your commit, you may adjust the
420 freeze limit by running:
421 git config %s <new_limit>
422 Where <new_limit> is an integer threshold in megabytes.""",
423 untracked_size, limit_mb, key)
392 424
393 try: 425 try:
394 run('commit', '--no-verify', '-m', FREEZE + '.indexed') 426 run('commit', '--no-verify', '-m', FREEZE + '.indexed')
395 took_action = True 427 took_action = True
396 except subprocess2.CalledProcessError: 428 except subprocess2.CalledProcessError:
397 pass 429 pass
398 430
399 try: 431 try:
400 run('add', '-A') 432 run('add', '-A')
401 run('commit', '--no-verify', '-m', FREEZE + '.unindexed') 433 run('commit', '--no-verify', '-m', FREEZE + '.unindexed')
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after
492 ret = run('hash-object', '-t', kind, '-w', '--stdin', stdin=f) 524 ret = run('hash-object', '-t', kind, '-w', '--stdin', stdin=f)
493 f.close() 525 f.close()
494 return ret 526 return ret
495 527
496 528
497 def is_dormant(branch): 529 def is_dormant(branch):
498 # TODO(iannucci): Do an oldness check? 530 # TODO(iannucci): Do an oldness check?
499 return branch_config(branch, 'dormant', 'false') != 'false' 531 return branch_config(branch, 'dormant', 'false') != 'false'
500 532
501 533
534 def is_unmerged(stat_value):
535 return (
536 'U' in (stat_value.lstat, stat_value.rstat) or
537 ((stat_value.lstat == stat_value.rstat) and stat_value.lstat in 'AD')
538 )
539
540
502 def manual_merge_base(branch, base, parent): 541 def manual_merge_base(branch, base, parent):
503 set_branch_config(branch, 'base', base) 542 set_branch_config(branch, 'base', base)
504 set_branch_config(branch, 'base-upstream', parent) 543 set_branch_config(branch, 'base-upstream', parent)
505 544
506 545
507 def mktree(treedict): 546 def mktree(treedict):
508 """Makes a git tree object and returns its hash. 547 """Makes a git tree object and returns its hash.
509 548
510 See |tree()| for the values of mode, type, and ref. 549 See |tree()| for the values of mode, type, and ref.
511 550
(...skipping 189 matching lines...) Expand 10 before | Expand all | Expand 10 after
701 if dirty: 740 if dirty:
702 print 'Cannot %s with a dirty tree. You must commit locally first.' % cmd 741 print 'Cannot %s with a dirty tree. You must commit locally first.' % cmd
703 print 'Uncommitted files: (git diff-index --name-status HEAD)' 742 print 'Uncommitted files: (git diff-index --name-status HEAD)'
704 print dirty[:4096] 743 print dirty[:4096]
705 if len(dirty) > 4096: # pragma: no cover 744 if len(dirty) > 4096: # pragma: no cover
706 print '... (run "git diff-index --name-status HEAD" to see full output).' 745 print '... (run "git diff-index --name-status HEAD" to see full output).'
707 return True 746 return True
708 return False 747 return False
709 748
710 749
750 def status():
751 """Returns a parsed version of git-status.
752
753 Returns a generator of (current_name, (lstat, rstat, src)) pairs where:
754 * current_name is the name of the file
755 * lstat is the left status code letter from git-status
756 * rstat is the left status code letter from git-status
757 * src is the current name of the file, or the original name of the file
758 if lstat == 'R'
759 """
760 stat_entry = collections.namedtuple('stat_entry', 'lstat rstat src')
761
762 def tokenizer(stream):
763 acc = StringIO()
764 c = None
765 while c != '':
766 c = stream.read(1)
767 if c in (None, '', '\0'):
768 s = acc.getvalue()
tandrii(chromium) 2016/06/21 14:43:37 nit: if you'd had used plain StringIO, which for t
agable 2016/06/22 11:16:51 Good point, done.
769 acc = StringIO()
770 if s:
771 yield s
772 else:
773 acc.write(c)
774
775 def parser(tokens):
776 END = object()
777 tok = lambda: next(tokens, END)
778 while True:
779 status_dest = tok()
780 if status_dest is END:
781 return
782 stat, dest = status_dest[:2], status_dest[3:]
tandrii(chromium) 2016/06/21 14:43:37 suggestion: why not plain old except to detect END
agable 2016/06/22 11:16:51 Nice, done.
783 lstat, rstat = stat
784 if lstat == 'R':
785 src = tok()
786 assert src is not END
787 else:
788 src = dest
789 yield (dest, stat_entry(lstat, rstat, src))
790
791 return parser(tokenizer(run_stream('status', '-z', bufsize=-1)))
792
793
711 def squash_current_branch(header=None, merge_base=None): 794 def squash_current_branch(header=None, merge_base=None):
712 header = header or 'git squash commit.' 795 header = header or 'git squash commit.'
713 merge_base = merge_base or get_or_create_merge_base(current_branch()) 796 merge_base = merge_base or get_or_create_merge_base(current_branch())
714 log_msg = header + '\n' 797 log_msg = header + '\n'
715 if log_msg: 798 if log_msg:
716 log_msg += '\n' 799 log_msg += '\n'
717 log_msg += run('log', '--reverse', '--format=%H%n%B', '%s..HEAD' % merge_base) 800 log_msg += run('log', '--reverse', '--format=%H%n%B', '%s..HEAD' % merge_base)
718 run('reset', '--soft', merge_base) 801 run('reset', '--soft', merge_base)
719 802
720 if not get_dirty_files(): 803 if not get_dirty_files():
(...skipping 191 matching lines...) Expand 10 before | Expand all | Expand 10 after
912 ['HEAD']) 995 ['HEAD'])
913 996
914 997
915 def clone_file(repository, new_workdir, link, operation): 998 def clone_file(repository, new_workdir, link, operation):
916 if not os.path.exists(os.path.join(repository, link)): 999 if not os.path.exists(os.path.join(repository, link)):
917 return 1000 return
918 link_dir = os.path.dirname(os.path.join(new_workdir, link)) 1001 link_dir = os.path.dirname(os.path.join(new_workdir, link))
919 if not os.path.exists(link_dir): 1002 if not os.path.exists(link_dir):
920 os.makedirs(link_dir) 1003 os.makedirs(link_dir)
921 operation(os.path.join(repository, link), os.path.join(new_workdir, link)) 1004 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') | tests/git_common_test.py » ('J')

Powered by Google App Engine
This is Rietveld 408576698