pre-upload: add cargo_fmt_check presubmit hook

This will be used to check formatting of Rust code.

BUG=chromium:908640
TEST=repo upload on platform2 and crosvm Rust code

Change-Id: I6d5f188e95b770deef17176fc3732362fa953e19
Signed-off-by: Daniel Verkamp <dverkamp@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/1352648
Reviewed-by: Chirantan Ekbote <chirantan@chromium.org>
diff --git a/pre-upload.py b/pre-upload.py
index 9ffa89c..48d7a2e 100755
--- a/pre-upload.py
+++ b/pre-upload.py
@@ -1216,6 +1216,36 @@
 # Project-specific hooks
 
 
+def _check_cargo_fmt(_project, _commit, options=()):
+  """Runs cargo fmt on the given project.
+
+  If specified, options is a list of directories to run cargo fmt in
+  (rather than at the root of the project).
+  """
+  pwd = os.getcwd()
+  cmd = ['cargo', 'fmt', '--all', '--', '--check']
+  errors = ''
+
+  # Check from the root of the project if no options were specified.
+  if not options:
+    options = ('.')
+
+  for path in options:
+    os.chdir(os.path.join(pwd, path))
+    cmd_result = cros_build_lib.RunCommand(cmd=cmd,
+                                           print_cmd=False,
+                                           stdout_to_pipe=True,
+                                           combine_stdout_stderr=True,
+                                           error_code_ok=True)
+    if cmd_result.returncode:
+      errors += cmd_result.output + '\n'
+
+  os.chdir(pwd)
+
+  if errors:
+    return HookFailure('cargo fmt errors\n\n' + errors)
+
+
 def _check_clang_format(_project, commit, options=()):
   """Runs clang-format on the given project"""
   hooks_dir = _get_hooks_dir()
@@ -1587,6 +1617,7 @@
 # A dictionary of flags (keys) that can appear in the config file, and the hook
 # that the flag controls (value).
 _HOOK_FLAGS = {
+    'cargo_fmt_check': _check_cargo_fmt,
     'clang_format_check': _check_clang_format,
     'checkpatch_check': _run_checkpatch,
     'stray_whitespace_check': _check_no_stray_whitespace,