| OLD | NEW | 
|---|
| (Empty) |  | 
|  | 1 #!/usr/bin/env python | 
|  | 2 # | 
|  | 3 # Copyright (c) 2013 The Chromium Authors. All rights reserved. | 
|  | 4 # Use of this source code is governed by a BSD-style license that can be | 
|  | 5 # found in the LICENSE file. | 
|  | 6 | 
|  | 7 """Runs Android's lint tool.""" | 
|  | 8 | 
|  | 9 | 
|  | 10 import optparse | 
|  | 11 import os | 
|  | 12 import sys | 
|  | 13 from xml.dom import minidom | 
|  | 14 | 
|  | 15 from util import build_utils | 
|  | 16 | 
|  | 17 | 
|  | 18 _SRC_ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), | 
|  | 19                                          '..', '..', '..')) | 
|  | 20 | 
|  | 21 | 
|  | 22 def _RunLint(lint_path, config_path, processed_config_path, manifest_path, | 
|  | 23              result_path, product_dir, src_dirs, classes_dir): | 
|  | 24 | 
|  | 25   def _RelativizePath(path): | 
|  | 26     """Returns relative path to top-level src dir. | 
|  | 27 | 
|  | 28     Args: | 
|  | 29       path: A path relative to cwd. | 
|  | 30     """ | 
|  | 31     return os.path.relpath(os.path.abspath(path), _SRC_ROOT) | 
|  | 32 | 
|  | 33   def _ProcessConfigFile(): | 
|  | 34     if not build_utils.IsTimeStale(processed_config_path, [config_path]): | 
|  | 35       return | 
|  | 36 | 
|  | 37     with open(config_path, 'rb') as f: | 
|  | 38       content = f.read().replace( | 
|  | 39           'PRODUCT_DIR', _RelativizePath(product_dir)) | 
|  | 40 | 
|  | 41     with open(processed_config_path, 'wb') as f: | 
|  | 42       f.write(content) | 
|  | 43 | 
|  | 44   def _ProcessResultFile(): | 
|  | 45     with open(result_path, 'rb') as f: | 
|  | 46       content = f.read().replace( | 
|  | 47           _RelativizePath(product_dir), 'PRODUCT_DIR') | 
|  | 48 | 
|  | 49     with open(result_path, 'wb') as f: | 
|  | 50       f.write(content) | 
|  | 51 | 
|  | 52   def _ParseAndShowResultFile(): | 
|  | 53     dom = minidom.parse(result_path) | 
|  | 54     issues = dom.getElementsByTagName('issue') | 
|  | 55     print >> sys.stderr | 
|  | 56     for issue in issues: | 
|  | 57       issue_id = issue.attributes['id'].value | 
|  | 58       severity = issue.attributes['severity'].value | 
|  | 59       message = issue.attributes['message'].value | 
|  | 60       location_elem = issue.getElementsByTagName('location')[0] | 
|  | 61       path = location_elem.attributes['file'].value | 
|  | 62       line = location_elem.getAttribute('line') | 
|  | 63       if line: | 
|  | 64         error = '%s:%s %s: %s [%s]' % (path, line, severity, message, | 
|  | 65                                        issue_id) | 
|  | 66       else: | 
|  | 67         # Issues in class files don't have a line number. | 
|  | 68         error = '%s %s: %s [%s]' % (path, severity, message, issue_id) | 
|  | 69       print >> sys.stderr, error | 
|  | 70       for attr in ['errorLine1', 'errorLine2']: | 
|  | 71         error_line = issue.getAttribute(attr) | 
|  | 72         if error_line: | 
|  | 73           print >> sys.stderr, error_line | 
|  | 74     return len(issues) | 
|  | 75 | 
|  | 76   _ProcessConfigFile() | 
|  | 77 | 
|  | 78   cmd = [ | 
|  | 79       lint_path, '-Werror', '--exitcode', '--showall', | 
|  | 80       '--config', _RelativizePath(processed_config_path), | 
|  | 81       '--classpath', _RelativizePath(classes_dir), | 
|  | 82       '--xml', _RelativizePath(result_path), | 
|  | 83   ] | 
|  | 84   for src in src_dirs: | 
|  | 85     cmd.extend(['--sources', _RelativizePath(src)]) | 
|  | 86   cmd.append(_RelativizePath(os.path.join(manifest_path, os.pardir))) | 
|  | 87 | 
|  | 88   if os.path.exists(result_path): | 
|  | 89     os.remove(result_path) | 
|  | 90 | 
|  | 91   try: | 
|  | 92     build_utils.CheckOutput(cmd, cwd=_SRC_ROOT) | 
|  | 93   except build_utils.CalledProcessError: | 
|  | 94     # There is a problem with lint usage | 
|  | 95     if not os.path.exists(result_path): | 
|  | 96       raise | 
|  | 97     # There are actual lint issues | 
|  | 98     else: | 
|  | 99       num_issues = _ParseAndShowResultFile() | 
|  | 100       _ProcessResultFile() | 
|  | 101       msg = ('\nLint found %d new issues.\n' | 
|  | 102              ' - For full explanation refer to %s\n' | 
|  | 103              ' - Wanna suppress these issues?\n' | 
|  | 104              '    1. Read comment in %s\n' | 
|  | 105              '    2. Run "python %s %s"\n' % | 
|  | 106              (num_issues, | 
|  | 107               _RelativizePath(result_path), | 
|  | 108               _RelativizePath(config_path), | 
|  | 109               _RelativizePath(os.path.join(_SRC_ROOT, 'build', 'android', | 
|  | 110                                            'lint', 'suppress.py')), | 
|  | 111               _RelativizePath(result_path))) | 
|  | 112       print >> sys.stderr, msg | 
|  | 113       return 1 | 
|  | 114 | 
|  | 115   return 0 | 
|  | 116 | 
|  | 117 | 
|  | 118 def main(argv): | 
|  | 119   parser = optparse.OptionParser() | 
|  | 120   parser.add_option('--lint-path', help='Path to lint executable.') | 
|  | 121   parser.add_option('--config-path', help='Path to lint suppressions file.') | 
|  | 122   parser.add_option('--processed-config-path', | 
|  | 123                     help='Path to processed lint suppressions file.') | 
|  | 124   parser.add_option('--manifest-path', help='Path to AndroidManifest.xml') | 
|  | 125   parser.add_option('--result-path', help='Path to XML lint result file.') | 
|  | 126   parser.add_option('--product-dir', help='Path to product dir.') | 
|  | 127   parser.add_option('--src-dirs', help='Directories containing java files.') | 
|  | 128   parser.add_option('--classes-dir', help='Directory containing class files.') | 
|  | 129   parser.add_option('--stamp', help='Path to touch on success.') | 
|  | 130   parser.add_option('--enable', action='store_true', | 
|  | 131                     help='Run lint instead of just touching stamp.') | 
|  | 132 | 
|  | 133   options, _ = parser.parse_args() | 
|  | 134 | 
|  | 135   build_utils.CheckOptions( | 
|  | 136       options, parser, required=['lint_path', 'config_path', | 
|  | 137                                  'processed_config_path', 'manifest_path', | 
|  | 138                                  'result_path', 'product_dir', 'src_dirs', | 
|  | 139                                  'classes_dir']) | 
|  | 140 | 
|  | 141   src_dirs = build_utils.ParseGypList(options.src_dirs) | 
|  | 142 | 
|  | 143   rc = 0 | 
|  | 144 | 
|  | 145   if options.enable: | 
|  | 146     rc = _RunLint(options.lint_path, options.config_path, | 
|  | 147                   options.processed_config_path, | 
|  | 148                   options.manifest_path, options.result_path, | 
|  | 149                   options.product_dir, src_dirs, options.classes_dir) | 
|  | 150 | 
|  | 151   if options.stamp and not rc: | 
|  | 152     build_utils.Touch(options.stamp) | 
|  | 153 | 
|  | 154   return rc | 
|  | 155 | 
|  | 156 | 
|  | 157 if __name__ == '__main__': | 
|  | 158   sys.exit(main(sys.argv)) | 
| OLD | NEW | 
|---|