patch-check: shfmt

shfmt is expected to be installed along with go.
GO111MODULE=on go install mvdan.cc/sh/v3/cmd/shfmt@latest

Change-Id: Iad569d20ef7452f579f50bfed7f1b22c6e99a227
Bug: b:185520494
diff --git a/PRESUBMIT.py b/PRESUBMIT.py
index df27862..df44427 100644
--- a/PRESUBMIT.py
+++ b/PRESUBMIT.py
@@ -35,6 +35,7 @@
 import subprocess2
 
 USE_PYTHON3 = True
+_BASH_INDENTATION = "2"
 _INCLUDE_BASH_FILES_ONLY = [r".*\.sh$"]
 _INCLUDE_SOURCE_FILES_ONLY = [r".*\.(c|cc|[hc]pp|h)$"]
 _LIBWEBM_MAX_LINE_LENGTH = 80
@@ -53,7 +54,6 @@
   cmd = ["shellcheck", "-x", "-oall", "-sbash", bash_file]
   name = "Check %s file." % bash_file
   start = input_api.time.time()
-  subprocess2.communicate(["shellcheck", "--version"])
   output, rc = subprocess2.communicate(
       cmd, stdout=None, stderr=subprocess2.PIPE, universal_newlines=True)
   duration = input_api.time.time() - start
@@ -64,15 +64,33 @@
                                    (name, " ".join(cmd), duration, output[1]))
 
 
-def _CheckChangedShellCheckClean(input_api, output_api):
-  """Ensure shell scripts are clean."""
-  bash_sources = lambda x: input_api.FilterSourceFile(
-      x, files_to_check=_INCLUDE_BASH_FILES_ONLY, files_to_skip=None)
+def _RunShfmtCheckCmd(input_api, output_api, bash_file):
+  """shfmt command wrapper."""
+  cmd = [
+      "shfmt", "-i", _BASH_INDENTATION, "-bn", "-ci", "-sr", "-kp", "-d",
+      bash_file
+  ]
+  name = "Check %s file." % bash_file
+  start = input_api.time.time()
+  output, rc = subprocess2.communicate(
+      cmd, stdout=None, stderr=subprocess2.PIPE, universal_newlines=True)
+  duration = input_api.time.time() - start
+  if rc == 0:
+    return output_api.PresubmitResult("%s\n%s (%4.2fs)\n" %
+                                      (name, " ".join(cmd), duration))
+  return output_api.PresubmitError("%s\n%s (%4.2fs) failed\n%s" %
+                                   (name, " ".join(cmd), duration, output[1]))
 
-  affected_bash_files = input_api.change.AffectedFiles(file_filter=bash_sources)
+
+def _RunCmdOnCheckedFiles(input_api, output_api, run_cmd, files_to_check):
+  """Ensure that libwebm/ files are clean."""
+  file_filter = lambda x: input_api.FilterSourceFile(
+      x, files_to_check=files_to_check, files_to_skip=None)
+
+  affected_files = input_api.change.AffectedFiles(file_filter=file_filter)
   results = [
-      _RunShellCheckCmd(input_api, output_api, bash_file.AbsoluteLocalPath())
-      for bash_file in affected_bash_files
+      run_cmd(input_api, output_api, f.AbsoluteLocalPath())
+      for f in affected_files
   ]
   return results
 
@@ -97,20 +115,34 @@
           check_clang_format=True,
           check_python=True,
           result_factory=output_api.PresubmitError))
+  results.extend(_CheckChangeLintsClean(input_api, output_api))
+
+  # Binaries shellcheck and shfmt are not installed in depot_tools.
+  # Installation is needed
+  try:
+    subprocess2.communicate(["shellcheck", "--version"])
+    results.extend(
+        _RunCmdOnCheckedFiles(input_api, output_api, _RunShellCheckCmd,
+                              _INCLUDE_BASH_FILES_ONLY))
+    print("shfmt")
+    subprocess2.communicate(["shfmt", "-version"])
+    results.extend(
+        _RunCmdOnCheckedFiles(input_api, output_api, _RunShfmtCheckCmd,
+                              _INCLUDE_BASH_FILES_ONLY))
+  except OSError as os_error:
+    results.append(
+        output_api.PresubmitPromptWarning(
+            "%s\nPlease install missing binaries locally." % os_error.args[0]))
   return results
 
 
 def CheckChangeOnUpload(input_api, output_api):
   results = []
   results.extend(_CommonChecks(input_api, output_api))
-  results.extend(_CheckChangeLintsClean(input_api, output_api))
-  results.extend(_CheckChangedShellCheckClean(input_api, output_api))
   return results
 
 
 def CheckChangeOnCommit(input_api, output_api):
   results = []
   results.extend(_CommonChecks(input_api, output_api))
-  results.extend(_CheckChangeLintsClean(input_api, output_api))
-  results.extend(_CheckChangedShellCheckClean(input_api, output_api))
   return results