Add new builder and builder stages for clang-tidy warnings.

This adds a new waterfall builder, with the appropriate new stages,
for generating clang-tidy warnings for chrome in the build logs,
parsing the build logs to generate warnings.{html,csv} files,
generating a tarball of the warnings files and uploading them to
gs.

BUG=chromium:687243
TEST=In the process of testing.

Change-Id: Id9c161aaaef999125fb454fc2537ea16ceb9ba4b
Reviewed-on: https://chromium-review.googlesource.com/985139
Commit-Ready: Caroline Tice <cmtice@chromium.org>
Tested-by: Caroline Tice <cmtice@chromium.org>
Reviewed-by: Caroline Tice <cmtice@chromium.org>
diff --git a/scripts/cros_generate_tidy_warnings.py b/scripts/cros_generate_tidy_warnings.py
new file mode 100644
index 0000000..4d64eee
--- /dev/null
+++ b/scripts/cros_generate_tidy_warnings.py
@@ -0,0 +1,90 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Generates a clang-tidy tarball for the clang-tidy builder."""
+
+from __future__ import print_function
+
+import os
+
+from chromite.lib import cros_build_lib
+from chromite.lib import commandline
+from chromite.lib import osutils
+from chromite.lib import sudo
+
+DEFAULT_NAME = 'clang_tidy_warnings.tar.xz'
+TIDY_WARNINGS = 'clang_tidy_warnings'
+PARSING_SCRIPT = '/usr/bin/clang-tidy-parse-build-log.py'
+WORKING_DIR = '/usr/bin'
+
+
+def ParseCommandLine(argv):
+  """Parse args, and run environment-independent checks."""
+  parser = commandline.ArgumentParser(description=__doc__)
+  parser.add_argument('--board', required=True,
+                      help=('The board to generate the sysroot for.'))
+  parser.add_argument('--files', required=True,
+                      help=('The files to generate warnings files for.'))
+  parser.add_argument('--out-dir', type='path', required=True,
+                      help='Directory to place the generated tarball.')
+  parser.add_argument('--out-file', default=DEFAULT_NAME,
+                      help='The name to give to the tarball. '
+                           'Defaults to %(default)s.')
+  options = parser.parse_args(argv)
+
+  return options
+
+
+class GenerateTidyWarnings(object):
+  """Wrapper for generation functionality."""
+
+  def __init__(self, warnings_dir, options):
+    """Initialize
+
+    Args:
+      warnings_dir: Path to warnings directory.
+      options: Parsed options.
+    """
+    self.warnings_dir = warnings_dir
+    self.options = options
+
+  def _ParseLogFiles(self):
+    log_files = self.options.files
+    for f in log_files:
+      cmd = [PARSING_SCRIPT, '--log_file', f, '--output_dir', self.warnings_dir]
+      cros_build_lib.RunCommand(cmd, cwd=WORKING_DIR, enter_chroot=True)
+
+  def _CreateTarball(self):
+    target = os.path.join(self.options.out_dir, self.options.out_file)
+    cros_build_lib.CreateTarball(target, self.warnings_dir, sudo=True)
+
+  def Perform(self):
+    """Generate the warnings files."""
+    self._ParseLogFiles()
+    self._CreateTarball()
+
+
+def FinishParsing(options):
+  """Run environment dependent checks on parsed args."""
+  target = os.path.join(options.out_dir, options.out_file)
+  if os.path.exists(target):
+    cros_build_lib.Die('Output file %r already exists.' % target)
+
+  if not os.path.isdir(options.out_dir):
+    cros_build_lib.Die(
+        'Non-existent directory %r specified for --out-dir' % options.out_dir)
+
+
+def main(argv):
+  options = ParseCommandLine(argv)
+  FinishParsing(options)
+
+  cros_build_lib.AssertInsideChroot()
+
+  with sudo.SudoKeepAlive(ttyless_sudo=False):
+    with osutils.TempDir(set_global=True, sudo_rm=True) as tempdir:
+      warnings_dir = os.path.join(tempdir, TIDY_WARNINGS)
+      os.mkdir(warnings_dir)
+      GenerateTidyWarnings(warnings_dir, options).Perform()