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

Unified Diff: git_common.py

Issue 311243003: Make git-freeze bail out if the user has too much untracked data. (Closed) Base URL: https://chromium.googlesource.com/chromium/tools/depot_tools.git@master
Patch Set: Address comments Created 6 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | git_map.py » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: git_common.py
diff --git a/git_common.py b/git_common.py
index 298ecc4ff3a8c9ee8f9263130b3751167b5eb5fa..55fb5c8b59af68e0f7a3041fbd01f6d640116e90 100644
--- a/git_common.py
+++ b/git_common.py
@@ -30,6 +30,8 @@ import threading
import subprocess2
+from cStringIO import StringIO
+
GIT_EXE = 'git.bat' if sys.platform.startswith('win') else 'git'
TEST_MODE = False
@@ -223,9 +225,13 @@ def once(function):
## Git functions
+def die(message, *args):
+ print >> sys.stderr, textwrap.dedent(message % args)
+ sys.exit(1)
+
def branch_config(branch, option, default=None):
- return config('branch.%s.%s' % (branch, option), default=default)
+ return get_config('branch.%s.%s' % (branch, option), default=default)
def branch_config_map(option):
@@ -242,23 +248,19 @@ def branches(*args):
NO_BRANCH = ('* (no branch', '* (detached from ')
key = 'depot-tools.branch-limit'
- limit = 20
- try:
- limit = int(config(key, limit))
- except ValueError:
- pass
+ limit = get_config_int(key, 20)
raw_branches = run('branch', *args).splitlines()
num = len(raw_branches)
+
if num > limit:
- print >> sys.stderr, textwrap.dedent("""\
- Your git repo has too many branches (%d/%d) for this tool to work well.
+ die("""\
+ Your git repo has too many branches (%d/%d) for this tool to work well.
- You may adjust this limit by running:
+ You may adjust this limit by running:
git config %s <new_limit>
- """ % (num, limit, key))
- sys.exit(1)
+ """, num, limit, key)
for line in raw_branches:
if line.startswith(NO_BRANCH):
@@ -275,14 +277,22 @@ def run_with_retcode(*cmd, **kwargs):
return cpe.returncode
-def config(option, default=None):
+def get_config(option, default=None):
try:
return run('config', '--get', option) or default
except subprocess2.CalledProcessError:
return default
-def config_list(option):
+def get_config_int(option, default=0):
+ assert isinstance(default, int)
+ try:
+ return int(get_config(option, default))
+ except ValueError:
+ return default
+
+
+def get_config_list(option):
try:
return run('config', '--get-all', option).split()
except subprocess2.CalledProcessError:
@@ -310,6 +320,38 @@ def del_config(option, scope='local'):
def freeze():
took_action = False
+ stat = status()
+ if any(is_unmerged(s) for s in stat.itervalues()):
+ die("Cannot freeze unmerged changes!")
+
+ key = 'depot-tools.freeze-size-limit'
+ MB = 2**20
+ limit_mb = get_config_int(key, 100)
+ if limit_mb > 0:
+ untracked_size = sum(
+ os.stat(f).st_size
+ for f, s in stat.iteritems() if s.lstat == '?'
+ ) / MB
+ if untracked_size > limit_mb:
+ die("""\
+ You appear to have too much untracked+unignored data in your git
+ checkout: %d/%dMB.
+
+ Run `git status` to see what it is.
+
+ In addition to making many git commands slower, this will prevent
+ depot_tools from freezing your in-progress changes.
+
+ You should add untracked data that you want to ignore to your repo's
+ .git/info/excludes
+ file. See `git help ignore` for the format of this file.
+
+ If this data is indended as part of your commit, you may adjust the
+ freeze limit by running:
+ git config %s <new_limit>
+ Where <new_limit> is an integer threshold in megabytes.""",
+ untracked_size, limit_mb, key)
+
try:
run('commit', '-m', FREEZE + '.indexed')
took_action = True
@@ -416,6 +458,13 @@ def is_dormant(branch):
return branch_config(branch, 'dormant', 'false') != 'false'
+def is_unmerged(stat_value):
+ return (
+ 'U' in (stat_value.lstat, stat_value.rstat) or
+ ((stat_value.lstat == stat_value.rstat) and stat_value.lstat in 'AD')
+ )
+
+
def manual_merge_base(branch, base, parent):
set_branch_config(branch, 'base', base)
set_branch_config(branch, 'base-upstream', parent)
@@ -487,7 +536,7 @@ def remove_merge_base(branch):
def root():
- return config('depot-tools.upstream', 'origin/master')
+ return get_config('depot-tools.upstream', 'origin/master')
def run(*cmd, **kwargs):
@@ -544,6 +593,50 @@ def set_branch_config(branch, option, value, scope='local'):
def set_config(option, value, scope='local'):
run('config', '--' + scope, option, value)
+
+def status():
+ """Returns a parsed version of git-status.
+
+ Returns a dictionary of {current_name: (lstat, rstat, src)} where:
+ * lstat is the left status code letter from git-status
+ * rstat is the left status code letter from git-status
+ * src is the current name of the file, or the original name of the file
+ if lstat == 'R'
+ """
+ stat_entry = collections.namedtuple('stat_entry', 'lstat rstat src')
+
+ def tokenizer(stream):
+ acc = StringIO()
+ c = None
+ while c != '':
+ c = stream.read(1)
+ if c in (None, '', '\0'):
+ s = acc.getvalue()
+ acc = StringIO()
+ if s:
+ yield s
+ else:
+ acc.write(c)
+
+ def parser(tokens):
+ END = object()
+ tok = lambda: next(tokens, END)
+ while True:
+ status_dest = tok()
+ if status_dest is END:
+ return
+ stat, dest = status_dest[:2], status_dest[3:]
+ lstat, rstat = stat
+ if lstat == 'R':
+ src = tok()
+ assert src is not END
+ else:
+ src = dest
+ yield (dest, stat_entry(lstat, rstat, src))
+
+ return dict(parser(tokenizer(run_stream('status', '-z', bufsize=-1))))
+
+
def squash_current_branch(header=None, merge_base=None):
header = header or 'git squash commit.'
merge_base = merge_base or get_or_create_merge_base(current_branch())
« no previous file with comments | « no previous file | git_map.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698