Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(590)

Side by Side Diff: build/android/lint.py

Issue 72273003: [Android] Upstream android lint script and run it on debug builders. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: rebase Created 7 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « build/android/buildbot/bb_run_bot.py ('k') | build/android/lint_suppressions.xml » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(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 import tempfile
14 from xml.dom import minidom
15
16 from pylib import cmd_helper
17 from pylib import constants
18
19
20 # Dirs relative to /src to exclude from source linting.
21 _EXCLUDE_SRC_DIRS = [
22 'third_party',
23 ]
24 # Dirs relative to out/<type> to exclude from class linting.
25 _EXCLUDE_CLASSES_DIRS = [
26 'gen/eyesfree_java',
newt (away) 2013/11/18 21:43:43 we could expand this list a lot: ./gen/android_su
27 ]
28 _LINT_EXE = os.path.join(constants.ANDROID_SDK_ROOT, 'tools', 'lint')
29 _DOC = ('\nSTOP! It looks like you want to suppress some lint errors:\n'
30 '- Have you tried identifing the offending patch?\n'
31 ' Ask the author for a fix and/or revert the patch.\n'
32 '- It is preferred to add suppressions in the code instead of\n'
33 ' sweeping it under the rug here. See:\n'
34 ' http://developer.android.com/tools/debugging/improving-w-lint.html\n'
35 '\n'
36 'Still reading?\n'
37 '- You can edit this file manually to suppress an issue\n'
38 ' globally if it is not applicable to the project.\n'
39 '- You can also rebaseline this file by:\n'
40 ' %s -r\n'
41 ' If the rebaseline is temporary, please make sure there is a bug\n'
42 ' filed and assigned to the author of the offending patch.\n')
43
44
45 def _GetClassesDirs():
46 """Get a list of absolute paths to compiled 'classes' directories."""
47 classes_dir = []
48 for dirpath, _, _ in os.walk(constants.GetOutDirectory()):
49 if any([dirpath.startswith(os.path.join(constants.GetOutDirectory(), x)) for
50 x in _EXCLUDE_CLASSES_DIRS]):
51 continue
52 if os.path.basename(dirpath) == 'classes':
53 classes_dir.append(dirpath)
54
55 assert classes_dir, 'Did not find class files. Did you build?'
56 return classes_dir
57
58
59 def _GetSrcDirs():
60 """Get a list of absolute paths to Java 'src' directories."""
61 source_dirs = []
62 for dirpath, _, _ in os.walk(constants.DIR_SOURCE_ROOT):
63 if any([dirpath.startswith(os.path.join(constants.DIR_SOURCE_ROOT, x)) for
64 x in _EXCLUDE_SRC_DIRS]):
65 continue
66 if os.path.basename(dirpath) == 'src' and 'java' in dirpath:
67 source_dirs.append(dirpath)
68
69 assert source_dirs, 'Did not find any src directories.'
70 return source_dirs
71
72
73 def _Lint(project_path, result_xml_path=None, report_html=False,
74 config_xml_path=None, src_dirs=None, classes_dirs=None):
75 """Execute the lint tool.
76
77 Args:
78 project_path: Absoluate path to the project dir containing the manifest.
79 result_xml_path: Result file generated by lint using --xml.
80 report_html: Whether to generate a pretty html report instead of outputing
81 to stdout.
82 config_xml_path: Config file passed to lint using --config.
83 src_dirs: List of absolute paths to Java 'src' dirs.
84 classes_dirs: List of absolute paths to 'classes' dirs.
85
86 Returns:
87 Non-zero on failure.
88 """
89
90 cmd = [_LINT_EXE, '-Werror', '--exitcode', '--showall']
91
92 if result_xml_path:
93 cmd.extend(['--xml', result_xml_path])
94
95 if report_html:
96 _, html_path = tempfile.mkstemp(prefix='lint_', suffix='.html')
97 cmd.extend(['--html', html_path])
98
99 if config_xml_path:
100 cmd.extend(['--config', config_xml_path])
101
102 if not src_dirs:
103 src_dirs = _GetSrcDirs()
104 for src in src_dirs:
105 cmd.extend(['--sources', os.path.relpath(src, constants.DIR_SOURCE_ROOT)])
106
107 if not classes_dirs:
108 classes_dirs = _GetClassesDirs()
109 for cls in classes_dirs:
110 if not os.path.isabs(cls):
111 cls = os.path.join(constants.GetOutDirectory(), cls)
112 cmd.extend(['--classpath', os.path.relpath(cls, constants.DIR_SOURCE_ROOT)])
113
114 cmd.append(project_path)
115 return cmd_helper.RunCmd(cmd, cwd=constants.DIR_SOURCE_ROOT)
116
117
118 def _Rebaseline(result_xml_path, config_xml_path, script_path):
119 """Create a config file which ignores all lint issues.
120
121 Args:
122 result_xml_path: Result file generated by lint using --xml.
123 config_xml_path: Config file passed to lint using --config.
124 script_path: Absolute path to the script being executed.
125 """
126 dom = minidom.parse(result_xml_path)
127 issues = {}
128 for issue in dom.getElementsByTagName('issue'):
129 issue_id = issue.attributes['id'].value
130 if issue_id not in issues:
131 issues[issue_id] = set()
132 issues[issue_id].add(
133 issue.getElementsByTagName('location')[0].attributes['file'].value)
134
135 # Get a list of globally ignored issues from existing config file.
136 globally_ignored_issues = []
137 if os.path.exists(config_xml_path):
138 dom = minidom.parse(config_xml_path)
139 for issue in dom.getElementsByTagName('issue'):
140 if issue.getAttribute('severity') == 'ignore':
141 globally_ignored_issues.append(issue.attributes['id'].value)
142
143 new_dom = minidom.getDOMImplementation().createDocument(None, 'lint', None)
144 top_element = new_dom.documentElement
145 comment = _DOC % os.path.relpath(script_path, constants.DIR_SOURCE_ROOT)
146 top_element.appendChild(new_dom.createComment(comment))
147 for issue_id, locations in issues.iteritems():
148 issue = new_dom.createElement('issue')
149 issue.attributes['id'] = issue_id
150 if issue_id in globally_ignored_issues:
151 print 'Warning: %s is suppresed globally.' % issue_id
152 issue.attributes['severity'] = 'ignore'
153 else:
154 for loc in locations:
155 ignore = new_dom.createElement('ignore')
156 ignore.attributes['path'] = loc
157 issue.appendChild(ignore)
158 top_element.appendChild(issue)
159
160 with open(config_xml_path, 'w') as f:
161 f.write(new_dom.toprettyxml(indent=' ', encoding='utf-8'))
162
163
164 def Run(project_path, config_xml_path, script_path, src_dirs, classes_dirs):
165 """
166 Args:
167 project_path: Absolute path to the project dir containing the manifest.
168 config_xml_path: Config file passed to lint using --config.
169 script_path: Absolute path to the script being executed.
170 src_dirs: List of absolute paths to Java 'src' dirs.
171 classes_dirs: List of absolute paths to 'classes' dirs.
172
173 Returns:
174 Non-zero on failure.
175 """
176 assert os.path.exists(project_path), 'No such project path: %s' % project_path
177
178 parser = optparse.OptionParser()
179 parser.add_option('-r', '--rebaseline',
180 action='store_true',
181 help='Rebaseline existing lint issues.')
182 parser.add_option('--release',
183 action='store_true',
184 help='Whether this is a Release build.')
185 parser.add_option('--html',
186 action='store_true',
187 help='Generate a html report instead of writing to stdout.')
188 options, _ = parser.parse_args()
189
190 if options.release:
191 constants.SetBuildType('Release')
192 else:
193 constants.SetBuildType('Debug')
194
195 rc = 0
196 if options.rebaseline:
197 result_xml_path = tempfile.NamedTemporaryFile()
198 _Lint(project_path, result_xml_path=result_xml_path.name, src_dirs=src_dirs,
199 classes_dirs=classes_dirs)
200 _Rebaseline(result_xml_path.name, config_xml_path, script_path)
201 print 'Updated %s' % config_xml_path
202 else:
203 rc = _Lint(project_path, report_html=options.html,
204 config_xml_path=config_xml_path, src_dirs=src_dirs,
205 classes_dirs=classes_dirs)
206 if rc:
207 print ('\nWanna suppress errors? Refer to %s' %
208 os.path.relpath(config_xml_path, constants.DIR_SOURCE_ROOT))
209
210 return rc
211
212
213 def main(argv):
214 project_path = os.path.join(constants.DIR_SOURCE_ROOT, 'chrome', 'android',
215 'testshell', 'java')
216 script_path = os.path.abspath(__file__)
217 config_xml_path = os.path.join(os.path.dirname(script_path),
218 'lint_suppressions.xml')
219
220 return Run(project_path, config_xml_path, script_path, None, None)
221
222
223 if __name__ == '__main__':
224 sys.exit(main(sys.argv))
OLDNEW
« no previous file with comments | « build/android/buildbot/bb_run_bot.py ('k') | build/android/lint_suppressions.xml » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698