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.
7 """Add all generated lint_result.xml files to suppressions.xml"""
14 from xml
.dom
import minidom
16 _BUILD_ANDROID_DIR
= os
.path
.join(os
.path
.dirname(__file__
), '..')
17 sys
.path
.append(_BUILD_ANDROID_DIR
)
19 from pylib
import constants
22 _THIS_FILE
= os
.path
.abspath(__file__
)
23 _CONFIG_PATH
= os
.path
.join(os
.path
.dirname(_THIS_FILE
), 'suppressions.xml')
25 '\nSTOP! It looks like you want to suppress some lint errors:\n'
26 '- Have you tried identifing the offending patch?\n'
27 ' Ask the author for a fix and/or revert the patch.\n'
28 '- It is preferred to add suppressions in the code instead of\n'
29 ' sweeping it under the rug here. See:\n\n'
30 ' http://developer.android.com/tools/debugging/improving-w-lint.html\n'
33 '- You can edit this file manually to suppress an issue\n'
34 ' globally if it is not applicable to the project.\n'
35 '- You can also automatically add issues found so for in the\n'
36 ' build process by running:\n\n'
37 ' ' + os
.path
.relpath(_THIS_FILE
, constants
.DIR_SOURCE_ROOT
) + '\n\n'
38 ' which will generate this file (Comments are not preserved).\n'
39 ' Note: PRODUCT_DIR will be substituted at run-time with actual\n'
40 ' directory path (e.g. out/Debug)\n'
44 _Issue
= collections
.namedtuple('Issue', ['severity', 'paths'])
47 def _ParseConfigFile(config_path
):
48 print 'Parsing %s' % config_path
50 dom
= minidom
.parse(config_path
)
51 for issue
in dom
.getElementsByTagName('issue'):
52 issue_id
= issue
.attributes
['id'].value
53 severity
= issue
.getAttribute('severity')
55 [p
.attributes
['path'].value
for p
in
56 issue
.getElementsByTagName('ignore')])
57 issues_dict
[issue_id
] = _Issue(severity
, paths
)
61 def _ParseAndMergeResultFile(result_path
, issues_dict
):
62 print 'Parsing and merging %s' % result_path
63 dom
= minidom
.parse(result_path
)
64 for issue
in dom
.getElementsByTagName('issue'):
65 issue_id
= issue
.attributes
['id'].value
66 severity
= issue
.attributes
['severity'].value
67 path
= issue
.getElementsByTagName('location')[0].attributes
['file'].value
68 if issue_id
not in issues_dict
:
69 issues_dict
[issue_id
] = _Issue(severity
, set())
70 issues_dict
[issue_id
].paths
.add(path
)
73 def _WriteConfigFile(config_path
, issues_dict
):
74 new_dom
= minidom
.getDOMImplementation().createDocument(None, 'lint', None)
75 top_element
= new_dom
.documentElement
76 top_element
.appendChild(new_dom
.createComment(_DOC
))
77 for issue_id
in sorted(issues_dict
.keys()):
78 severity
= issues_dict
[issue_id
].severity
79 paths
= issues_dict
[issue_id
].paths
80 issue
= new_dom
.createElement('issue')
81 issue
.attributes
['id'] = issue_id
83 issue
.attributes
['severity'] = severity
84 if severity
== 'ignore':
85 print 'Warning: [%s] is suppressed globally.' % issue_id
87 for path
in sorted(paths
):
88 ignore
= new_dom
.createElement('ignore')
89 ignore
.attributes
['path'] = path
90 issue
.appendChild(ignore
)
91 top_element
.appendChild(issue
)
93 with
open(config_path
, 'w') as f
:
94 f
.write(new_dom
.toprettyxml(indent
=' ', encoding
='utf-8'))
95 print 'Updated %s' % config_path
98 def _Suppress(config_path
, result_path
):
99 issues_dict
= _ParseConfigFile(config_path
)
100 _ParseAndMergeResultFile(result_path
, issues_dict
)
101 _WriteConfigFile(config_path
, issues_dict
)
105 parser
= optparse
.OptionParser(usage
='%prog RESULT-FILE')
106 _
, args
= parser
.parse_args()
108 if len(args
) != 1 or not os
.path
.exists(args
[0]):
109 parser
.error('Must provide RESULT-FILE')
111 _Suppress(_CONFIG_PATH
, args
[0])
114 if __name__
== '__main__':