Add a canned clang-format presubmit check

For simplicity, the canned presubmit check just calls git cl format
directly with a new option --dry-run which does not change the files on
disk.

Because some users may not have git or clang-format might somehow have
errors, this canned check is a warning.  Additionally, if git cl format
fails with an error then the presubmit check will silently report
success to avoid spamming misconfigured users during upload.

BUG=none

Review URL: https://codereview.chromium.org/141493002

git-svn-id: svn://svn.chromium.org/chrome/trunk/tools/depot_tools@246066 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/git_cl.py b/git_cl.py
index f6c1ae7..d9e2d98 100755
--- a/git_cl.py
+++ b/git_cl.py
@@ -80,15 +80,20 @@
   return RunCommand(['git'] + args, **kwargs)
 
 
-def RunGitWithCode(args):
+def RunGitWithCode(args, suppress_stderr=False):
   """Returns return code and stdout."""
   try:
     env = os.environ.copy()
     # 'cat' is a magical git string that disables pagers on all platforms.
     env['GIT_PAGER'] = 'cat'
+    if suppress_stderr:
+      stderr = subprocess2.VOID
+    else:
+      stderr = sys.stderr
     out, code = subprocess2.communicate(['git'] + args,
                                         env=env,
-                                        stdout=subprocess2.PIPE)
+                                        stdout=subprocess2.PIPE,
+                                        stderr=stderr)
     return code, out[0]
   except ValueError:
     # When the subprocess fails, it returns None.  That triggers a ValueError
@@ -2301,7 +2306,10 @@
 def CMDformat(parser, args):
   """Runs clang-format on the diff."""
   CLANG_EXTS = ['.cc', '.cpp', '.h']
-  parser.add_option('--full', action='store_true', default=False)
+  parser.add_option('--full', action='store_true',
+                    help='Reformat the full content of all touched files')
+  parser.add_option('--dry-run', action='store_true',
+                    help='Don\'t modify any file on disk.')
   opts, args = parser.parse_args(args)
   if args:
     parser.error('Unrecognized args: %s' % ' '.join(args))
@@ -2358,8 +2366,10 @@
     if not files:
       print "Nothing to format."
       return 0
-    RunCommand([clang_format_tool, '-i'] + files,
-               cwd=top_dir)
+    cmd = [clang_format_tool]
+    if not opts.dry_run:
+      cmd.append('-i')
+    stdout = RunCommand(cmd + files, cwd=top_dir)
   else:
     env = os.environ.copy()
     env['PATH'] = os.path.dirname(clang_format_tool)
@@ -2370,9 +2380,13 @@
     except clang_format.NotFoundError, e:
       DieWithError(e)
 
-    cmd = [sys.executable, script, '-p0', '-i']
+    cmd = [sys.executable, script, '-p0']
+    if not opts.dry_run:
+      cmd.append('-i')
 
-    RunCommand(cmd, stdin=diff_output, cwd=top_dir, env=env)
+    stdout = RunCommand(cmd, stdin=diff_output, cwd=top_dir, env=env)
+    if opts.dry_run and len(stdout) > 0:
+      return 2
 
   return 0