OLD | NEW |
1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
2 # | 2 # |
3 # Copyright (c) 2013 The Chromium Authors. All rights reserved. | 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 | 4 # Use of this source code is governed by a BSD-style license that can be |
5 # found in the LICENSE file. | 5 # found in the LICENSE file. |
6 | 6 |
7 """Add all generated lint_result.xml files to suppressions.xml""" | 7 """Add all generated lint_result.xml files to suppressions.xml""" |
8 | 8 |
9 # pylint: disable=no-member | 9 # pylint: disable=no-member |
10 | 10 |
(...skipping 25 matching lines...) Expand all Loading... |
36 ' globally if it is not applicable to the project.\n' | 36 ' globally if it is not applicable to the project.\n' |
37 '- You can also automatically add issues found so for in the\n' | 37 '- You can also automatically add issues found so for in the\n' |
38 ' build process by running:\n\n' | 38 ' build process by running:\n\n' |
39 ' ' + os.path.relpath(_THIS_FILE, host_paths.DIR_SOURCE_ROOT) + '\n\n' | 39 ' ' + os.path.relpath(_THIS_FILE, host_paths.DIR_SOURCE_ROOT) + '\n\n' |
40 ' which will generate this file (Comments are not preserved).\n' | 40 ' which will generate this file (Comments are not preserved).\n' |
41 ' Note: PRODUCT_DIR will be substituted at run-time with actual\n' | 41 ' Note: PRODUCT_DIR will be substituted at run-time with actual\n' |
42 ' directory path (e.g. out/Debug)\n' | 42 ' directory path (e.g. out/Debug)\n' |
43 ) | 43 ) |
44 | 44 |
45 | 45 |
46 _Issue = collections.namedtuple('Issue', ['severity', 'paths']) | 46 _Issue = collections.namedtuple('Issue', ['severity', 'paths', 'regexps']) |
47 | 47 |
48 | 48 |
49 def _ParseConfigFile(config_path): | 49 def _ParseConfigFile(config_path): |
50 print 'Parsing %s' % config_path | 50 print 'Parsing %s' % config_path |
51 issues_dict = {} | 51 issues_dict = {} |
52 dom = minidom.parse(config_path) | 52 dom = minidom.parse(config_path) |
53 for issue in dom.getElementsByTagName('issue'): | 53 for issue in dom.getElementsByTagName('issue'): |
54 issue_id = issue.attributes['id'].value | 54 issue_id = issue.attributes['id'].value |
55 severity = issue.getAttribute('severity') | 55 severity = issue.getAttribute('severity') |
56 paths = set( | 56 |
57 [p.attributes['path'].value for p in | 57 path_elements = ( |
58 issue.getElementsByTagName('ignore')]) | 58 p.attributes.get('path') |
59 issues_dict[issue_id] = _Issue(severity, paths) | 59 for p in issue.getElementsByTagName('ignore')) |
| 60 paths = set(p.value for p in path_elements if p) |
| 61 |
| 62 regexp_elements = ( |
| 63 p.attributes.get('regexp') |
| 64 for p in issue.getElementsByTagName('ignore')) |
| 65 regexps = set(r.value for r in regexp_elements if r) |
| 66 |
| 67 issues_dict[issue_id] = _Issue(severity, paths, regexps) |
60 return issues_dict | 68 return issues_dict |
61 | 69 |
62 | 70 |
63 def _ParseAndMergeResultFile(result_path, issues_dict): | 71 def _ParseAndMergeResultFile(result_path, issues_dict): |
64 print 'Parsing and merging %s' % result_path | 72 print 'Parsing and merging %s' % result_path |
65 dom = minidom.parse(result_path) | 73 dom = minidom.parse(result_path) |
66 for issue in dom.getElementsByTagName('issue'): | 74 for issue in dom.getElementsByTagName('issue'): |
67 issue_id = issue.attributes['id'].value | 75 issue_id = issue.attributes['id'].value |
68 severity = issue.attributes['severity'].value | 76 severity = issue.attributes['severity'].value |
69 path = issue.getElementsByTagName('location')[0].attributes['file'].value | 77 path = issue.getElementsByTagName('location')[0].attributes['file'].value |
70 if issue_id not in issues_dict: | 78 if issue_id not in issues_dict: |
71 issues_dict[issue_id] = _Issue(severity, set()) | 79 issues_dict[issue_id] = _Issue(severity, set(), set()) |
72 issues_dict[issue_id].paths.add(path) | 80 issues_dict[issue_id].paths.add(path) |
73 | 81 |
74 | 82 |
75 def _WriteConfigFile(config_path, issues_dict): | 83 def _WriteConfigFile(config_path, issues_dict): |
76 new_dom = minidom.getDOMImplementation().createDocument(None, 'lint', None) | 84 new_dom = minidom.getDOMImplementation().createDocument(None, 'lint', None) |
77 top_element = new_dom.documentElement | 85 top_element = new_dom.documentElement |
78 top_element.appendChild(new_dom.createComment(_DOC)) | 86 top_element.appendChild(new_dom.createComment(_DOC)) |
79 for issue_id in sorted(issues_dict.keys()): | 87 for issue_id, issue in sorted(issues_dict.iteritems(), key=lambda i: i[0]): |
80 severity = issues_dict[issue_id].severity | 88 issue_element = new_dom.createElement('issue') |
81 paths = issues_dict[issue_id].paths | 89 issue_element.attributes['id'] = issue_id |
82 issue = new_dom.createElement('issue') | 90 if issue.severity: |
83 issue.attributes['id'] = issue_id | 91 issue_element.attributes['severity'] = issue.severity |
84 if severity: | 92 if issue.severity == 'ignore': |
85 issue.attributes['severity'] = severity | |
86 if severity == 'ignore': | |
87 print 'Warning: [%s] is suppressed globally.' % issue_id | 93 print 'Warning: [%s] is suppressed globally.' % issue_id |
88 else: | 94 else: |
89 for path in sorted(paths): | 95 for path in sorted(issue.paths): |
90 ignore = new_dom.createElement('ignore') | 96 ignore_element = new_dom.createElement('ignore') |
91 ignore.attributes['path'] = path | 97 ignore_element.attributes['path'] = path |
92 issue.appendChild(ignore) | 98 issue_element.appendChild(ignore_element) |
93 top_element.appendChild(issue) | 99 for regexp in sorted(issue.regexps): |
| 100 ignore_element = new_dom.createElement('ignore') |
| 101 ignore_element.attributes['regexp'] = regexp |
| 102 issue_element.appendChild(ignore_element) |
| 103 top_element.appendChild(issue_element) |
94 | 104 |
95 with open(config_path, 'w') as f: | 105 with open(config_path, 'w') as f: |
96 f.write(new_dom.toprettyxml(indent=' ', encoding='utf-8')) | 106 f.write(new_dom.toprettyxml(indent=' ', encoding='utf-8')) |
97 print 'Updated %s' % config_path | 107 print 'Updated %s' % config_path |
98 | 108 |
99 | 109 |
100 def _Suppress(config_path, result_path): | 110 def _Suppress(config_path, result_path): |
101 issues_dict = _ParseConfigFile(config_path) | 111 issues_dict = _ParseConfigFile(config_path) |
102 _ParseAndMergeResultFile(result_path, issues_dict) | 112 _ParseAndMergeResultFile(result_path, issues_dict) |
103 _WriteConfigFile(config_path, issues_dict) | 113 _WriteConfigFile(config_path, issues_dict) |
104 | 114 |
105 | 115 |
106 def main(): | 116 def main(): |
107 parser = optparse.OptionParser(usage='%prog RESULT-FILE') | 117 parser = optparse.OptionParser(usage='%prog RESULT-FILE') |
108 _, args = parser.parse_args() | 118 _, args = parser.parse_args() |
109 | 119 |
110 if len(args) != 1 or not os.path.exists(args[0]): | 120 if len(args) != 1 or not os.path.exists(args[0]): |
111 parser.error('Must provide RESULT-FILE') | 121 parser.error('Must provide RESULT-FILE') |
112 | 122 |
113 _Suppress(_CONFIG_PATH, args[0]) | 123 _Suppress(_CONFIG_PATH, args[0]) |
114 | 124 |
115 | 125 |
116 if __name__ == '__main__': | 126 if __name__ == '__main__': |
117 main() | 127 main() |
OLD | NEW |