Block files >10MB in a presubmit check

To avoid bloating the chromium/src git repo with large binary
files, this adds a check that files are not too large and suggests
to use cloud storage otherwise.

Bug: 956017
Change-Id: Idf6e816a50030551fc6003b0f83b2071f685c9b5
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1581803
Reviewed-by: Dirk Pranke <dpranke@chromium.org>
Commit-Queue: Daniel Bratell <bratell@opera.com>
Cr-Commit-Position: refs/heads/master@{#653733}
diff --git a/PRESUBMIT.py b/PRESUBMIT.py
index ab8ed74..d097eff 100644
--- a/PRESUBMIT.py
+++ b/PRESUBMIT.py
@@ -3271,6 +3271,34 @@
     return []
 
 
+def _CheckForTooLargeFiles(input_api, output_api):
+  """Avoid large files, especially binary files, in the repository since
+  git doesn't scale well for those. They will be in everyone's repo
+  clones forever, forever making Chromium slower to clone and work
+  with."""
+
+  # Uploading files to cloud storage is not trivial so we don't want
+  # to set the limit too low, but the upper limit for "normal" large
+  # files seems to be 1-2 MB so anything over 10 MB is exceptional.
+  TOO_LARGE_FILE_SIZE_LIMIT = 10 * 1024 * 1024  # 10 MB
+
+  too_large_files = []
+  for f in input_api.AffectedFiles():
+    size = input_api.os_path.getsize(f.LocalPath())
+    if size > TOO_LARGE_FILE_SIZE_LIMIT:
+      too_large_files.append("%s: %d bytes" % (f.LocalPath(), size))
+
+  if too_large_files:
+    message = (
+      'Do not commit large files to git since git scales badly for those.\n' +
+      'Instead put the large files in cloud storage and use DEPS to\n' +
+      'fetch them.\n' + '\n'.join(too_large_files)
+    )
+    return [output_api.PresubmitError(
+        'Too large files found in commit', long_text=message + '\n')]
+  else:
+    return []
+
 def _AndroidSpecificOnUploadChecks(input_api, output_api):
   """Groups upload checks that target android code."""
   results = []
@@ -3358,6 +3386,7 @@
   results.extend(_CheckTranslationScreenshots(input_api, output_api))
   results.extend(_CheckCorrectProductNameInMessages(input_api, output_api))
   results.extend(_CheckBuildtoolsRevisionsAreInSync(input_api, output_api))
+  results.extend(_CheckForTooLargeFiles(input_api, output_api))
 
   for f in input_api.AffectedFiles():
     path, name = input_api.os_path.split(f.LocalPath())