1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
|
#!/usr/bin/env python
#
# Copyright (c) 2013 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Add all generated lint_result.xml files to suppressions.xml"""
# pylint: disable=no-member
from __future__ import print_function
import argparse
import os
import re
import sys
from xml.dom import minidom
_BUILD_ANDROID_DIR = os.path.join(os.path.dirname(__file__), '..')
sys.path.append(_BUILD_ANDROID_DIR)
_TMP_DIR_RE = re.compile(r'^/tmp/.*/(SRC_ROOT[0-9]+|PRODUCT_DIR)/')
_THIS_FILE = os.path.abspath(__file__)
_DEFAULT_CONFIG_PATH = os.path.join(os.path.dirname(_THIS_FILE),
'suppressions.xml')
_INSERT_COMMENT = ('TODO: This line was added by suppress.py,'
' please add an explanation.')
class _Issue(object):
def __init__(self, dom_element):
self.regexps = set()
self.dom_element = dom_element
def _CollectIssuesFromDom(dom):
issues_dict = {}
for issue_element in dom.getElementsByTagName('issue'):
issue_id = issue_element.attributes['id'].value
issue = _Issue(issue_element)
issues_dict[issue_id] = issue
for child in issue_element.childNodes:
if child.nodeType != minidom.Node.ELEMENT_NODE:
continue
if child.tagName == 'ignore' and child.getAttribute('regexp'):
issue.regexps.add(child.getAttribute('regexp'))
return issues_dict
def _TrimWhitespaceNodes(n):
"""Remove all whitespace-only TEXT_NODEs."""
rm_children = []
for c in n.childNodes:
if c.nodeType == minidom.Node.TEXT_NODE and c.data.strip() == '':
rm_children.append(c)
else:
_TrimWhitespaceNodes(c)
for c in rm_children:
n.removeChild(c)
def _ParseAndInsertNewSuppressions(result_path, config_path):
print('Parsing %s' % config_path)
config_dom = minidom.parse(config_path)
issues_dict = _CollectIssuesFromDom(config_dom)
print('Parsing and merging %s' % result_path)
dom = minidom.parse(result_path)
for issue_element in dom.getElementsByTagName('issue'):
issue_id = issue_element.attributes['id'].value
severity = issue_element.attributes['severity'].value
path = issue_element.getElementsByTagName(
'location')[0].attributes['file'].value
# Strip temporary file path.
path = re.sub(_TMP_DIR_RE, '', path)
# Escape Java inner class name separator and suppress with regex instead
# of path. Doesn't use re.escape() as it is a bit too aggressive and
# escapes '_', causing trouble with PRODUCT_DIR.
regexp = path.replace('$', r'\$')
if issue_id not in issues_dict:
element = config_dom.createElement('issue')
element.attributes['id'] = issue_id
element.attributes['severity'] = severity
config_dom.documentElement.appendChild(element)
issue = _Issue(element)
issues_dict[issue_id] = issue
else:
issue = issues_dict[issue_id]
if issue.dom_element.getAttribute('severity') == 'ignore':
continue
if regexp not in issue.regexps:
issue.regexps.add(regexp)
ignore_element = config_dom.createElement('ignore')
ignore_element.attributes['regexp'] = regexp
issue.dom_element.appendChild(config_dom.createComment(_INSERT_COMMENT))
issue.dom_element.appendChild(ignore_element)
for issue_id, issue in issues_dict.iteritems():
if issue.dom_element.getAttribute('severity') == 'ignore':
print('Warning: [%s] is suppressed globally.' % issue_id)
# toprettyxml inserts whitespace, so delete whitespace first.
_TrimWhitespaceNodes(config_dom.documentElement)
with open(config_path, 'w') as f:
f.write(config_dom.toprettyxml(indent=' ', encoding='utf-8'))
print('Updated %s' % config_path)
def _Suppress(config_path, result_path):
_ParseAndInsertNewSuppressions(result_path, config_path)
def main():
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument('--config',
help='Path to suppression.xml config file',
default=_DEFAULT_CONFIG_PATH)
parser.add_argument('result_path',
help='Lint results xml file',
metavar='RESULT_FILE')
args = parser.parse_args()
_Suppress(args.config, args.result_path)
if __name__ == '__main__':
main()
|