1a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#!/usr/bin/env python 2a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)# 3a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)# Copyright (c) 2013 The Chromium Authors. All rights reserved. 4a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)# Use of this source code is governed by a BSD-style license that can be 5a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)# found in the LICENSE file. 6a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 7a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)"""Add all generated lint_result.xml files to suppressions.xml""" 8a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 9a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 10a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)import collections 11a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)import optparse 12a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)import os 13a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)import sys 14a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)from xml.dom import minidom 15a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 16a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)_BUILD_ANDROID_DIR = os.path.join(os.path.dirname(__file__), '..') 17a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)sys.path.append(_BUILD_ANDROID_DIR) 18a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 19a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)from pylib import constants 20a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 21a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 22a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)_THIS_FILE = os.path.abspath(__file__) 23a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)_CONFIG_PATH = os.path.join(os.path.dirname(_THIS_FILE), 'suppressions.xml') 24a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)_DOC = ( 25a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) '\nSTOP! It looks like you want to suppress some lint errors:\n' 26a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) '- Have you tried identifing the offending patch?\n' 27a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) ' Ask the author for a fix and/or revert the patch.\n' 28a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) '- It is preferred to add suppressions in the code instead of\n' 29a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) ' sweeping it under the rug here. See:\n\n' 30a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) ' http://developer.android.com/tools/debugging/improving-w-lint.html\n' 31a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) '\n' 32a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 'Still reading?\n' 33a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) '- You can edit this file manually to suppress an issue\n' 34a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) ' globally if it is not applicable to the project.\n' 35a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) '- You can also automatically add issues found so for in the\n' 36a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) ' build process by running:\n\n' 37a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) ' ' + os.path.relpath(_THIS_FILE, constants.DIR_SOURCE_ROOT) + '\n\n' 38a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) ' which will generate this file (Comments are not preserved).\n' 39a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) ' Note: PRODUCT_DIR will be substituted at run-time with actual\n' 40a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) ' directory path (e.g. out/Debug)\n' 41a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)) 42a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 43a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 44a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)_Issue = collections.namedtuple('Issue', ['severity', 'paths']) 45a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 46a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 47a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)def _ParseConfigFile(config_path): 48a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) print 'Parsing %s' % config_path 49a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) issues_dict = {} 50a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) dom = minidom.parse(config_path) 51a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) for issue in dom.getElementsByTagName('issue'): 52a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) issue_id = issue.attributes['id'].value 53a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) severity = issue.getAttribute('severity') 54a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) paths = set( 55a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) [p.attributes['path'].value for p in 56a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) issue.getElementsByTagName('ignore')]) 57a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) issues_dict[issue_id] = _Issue(severity, paths) 58a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) return issues_dict 59a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 60a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 61a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)def _ParseAndMergeResultFile(result_path, issues_dict): 62a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) print 'Parsing and merging %s' % result_path 63a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) dom = minidom.parse(result_path) 64a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) for issue in dom.getElementsByTagName('issue'): 65a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) issue_id = issue.attributes['id'].value 66a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) severity = issue.attributes['severity'].value 67a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) path = issue.getElementsByTagName('location')[0].attributes['file'].value 68a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if issue_id not in issues_dict: 69a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) issues_dict[issue_id] = _Issue(severity, set()) 70a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) issues_dict[issue_id].paths.add(path) 71a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 72a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 73a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)def _WriteConfigFile(config_path, issues_dict): 74a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) new_dom = minidom.getDOMImplementation().createDocument(None, 'lint', None) 75a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) top_element = new_dom.documentElement 76a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) top_element.appendChild(new_dom.createComment(_DOC)) 77a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) for issue_id in sorted(issues_dict.keys()): 78a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) severity = issues_dict[issue_id].severity 79a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) paths = issues_dict[issue_id].paths 80a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) issue = new_dom.createElement('issue') 81a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) issue.attributes['id'] = issue_id 82a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if severity: 83a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) issue.attributes['severity'] = severity 84a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if severity == 'ignore': 85a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) print 'Warning: [%s] is suppressed globally.' % issue_id 86a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) else: 87a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) for path in sorted(paths): 88a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) ignore = new_dom.createElement('ignore') 89a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) ignore.attributes['path'] = path 90a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) issue.appendChild(ignore) 91a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) top_element.appendChild(issue) 92a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 93a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) with open(config_path, 'w') as f: 94a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) f.write(new_dom.toprettyxml(indent=' ', encoding='utf-8')) 95a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) print 'Updated %s' % config_path 96a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 97a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 98a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)def _Suppress(config_path, result_path): 99a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) issues_dict = _ParseConfigFile(config_path) 100a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) _ParseAndMergeResultFile(result_path, issues_dict) 101a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) _WriteConfigFile(config_path, issues_dict) 102a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 103a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 104effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochdef main(): 105a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) parser = optparse.OptionParser(usage='%prog RESULT-FILE') 106a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) _, args = parser.parse_args() 107a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 108a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if len(args) != 1 or not os.path.exists(args[0]): 109a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) parser.error('Must provide RESULT-FILE') 110a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 111a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) _Suppress(_CONFIG_PATH, args[0]) 112a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 113a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 114a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)if __name__ == '__main__': 115effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch main() 116