| OLD | NEW |
| 1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
| 2 # Copyright 2014 The Chromium Authors. All rights reserved. | 2 # Copyright 2014 The Chromium Authors. All rights reserved. |
| 3 # Use of this source code is governed by a BSD-style license that can be | 3 # Use of this source code is governed by a BSD-style license that can be |
| 4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
| 5 | 5 |
| 6 """A tool to scan source files for unneeded grit includes.""" | 6 """A tool to scan source files for unneeded grit includes. |
| 7 |
| 8 Example: |
| 9 cd /work/chrome/src |
| 10 tools/resources/list_unused_grit_header.py ui/strings/ui_strings.grd chrome ui |
| 11 """ |
| 7 | 12 |
| 8 import os | 13 import os |
| 9 import sys | 14 import sys |
| 10 import xml.etree.ElementTree | 15 import xml.etree.ElementTree |
| 11 | 16 |
| 17 from find_unused_resources import GetBaseResourceId |
| 18 |
| 12 IF_ELSE_TAGS = ('if', 'else') | 19 IF_ELSE_TAGS = ('if', 'else') |
| 13 | 20 |
| 14 | 21 |
| 15 def Usage(prog_name): | 22 def Usage(prog_name): |
| 16 print prog_name, 'GRD_FILE DIRS_TO_SCAN' | 23 print prog_name, 'GRD_FILE PATHS_TO_SCAN' |
| 24 |
| 25 |
| 26 def FilterResourceIds(resource_id): |
| 27 """If the resource starts with IDR_, find its base resource id.""" |
| 28 if resource_id.startswith('IDR_'): |
| 29 return GetBaseResourceId(resource_id) |
| 30 return resource_id |
| 17 | 31 |
| 18 | 32 |
| 19 def GetResourcesForNode(node, parent_file, resource_tag): | 33 def GetResourcesForNode(node, parent_file, resource_tag): |
| 20 """Recursively iterate through a node and extract resource names. | 34 """Recursively iterate through a node and extract resource names. |
| 21 | 35 |
| 22 Args: | 36 Args: |
| 23 node: The node to iterate through. | 37 node: The node to iterate through. |
| 24 parent_file: The file that contains node. | 38 parent_file: The file that contains node. |
| 25 resource_tag: The resource tag to extract names from. | 39 resource_tag: The resource tag to extract names from. |
| 26 | 40 |
| 27 Returns: | 41 Returns: |
| 28 A list of resource names. | 42 A list of resource names. |
| 29 """ | 43 """ |
| 30 resources = [] | 44 resources = [] |
| 31 for child in node.getchildren(): | 45 for child in node.getchildren(): |
| 32 if child.tag == resource_tag: | 46 if child.tag == resource_tag: |
| 33 resources.append(child.attrib['name']) | 47 resources.append(child.attrib['name']) |
| 34 elif child.tag in IF_ELSE_TAGS: | 48 elif child.tag in IF_ELSE_TAGS: |
| 35 resources.extend(GetResourcesForNode(child, parent_file, resource_tag)) | 49 resources.extend(GetResourcesForNode(child, parent_file, resource_tag)) |
| 36 elif child.tag == 'part': | 50 elif child.tag == 'part': |
| 37 parent_dir = os.path.dirname(parent_file) | 51 parent_dir = os.path.dirname(parent_file) |
| 38 part_file = os.path.join(parent_dir, child.attrib['file']) | 52 part_file = os.path.join(parent_dir, child.attrib['file']) |
| 39 part_tree = xml.etree.ElementTree.parse(part_file) | 53 part_tree = xml.etree.ElementTree.parse(part_file) |
| 40 part_root = part_tree.getroot() | 54 part_root = part_tree.getroot() |
| 41 assert part_root.tag == 'grit-part' | 55 assert part_root.tag == 'grit-part' |
| 42 resources.extend(GetResourcesForNode(part_root, part_file, resource_tag)) | 56 resources.extend(GetResourcesForNode(part_root, part_file, resource_tag)) |
| 43 else: | 57 else: |
| 44 raise Exception('unknown tag:', child.tag) | 58 raise Exception('unknown tag:', child.tag) |
| 59 |
| 60 # Handle the special case for resources of type "FOO_{LEFT,RIGHT,TOP}". |
| 61 if resource_tag == 'structure': |
| 62 resources = [FilterResourceIds(resource_id) for resource_id in resources] |
| 45 return resources | 63 return resources |
| 46 | 64 |
| 47 | 65 |
| 48 def FindNodeWithTag(node, tag): | 66 def FindNodeWithTag(node, tag): |
| 49 """Look through a node's children for a child node with a given tag. | 67 """Look through a node's children for a child node with a given tag. |
| 50 | 68 |
| 51 Args: | 69 Args: |
| 52 root: The node to examine. | 70 root: The node to examine. |
| 53 tag: The tag on a child node to look for. | 71 tag: The tag on a child node to look for. |
| 54 | 72 |
| (...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 143 grit_header: The grit header file name. | 161 grit_header: The grit header file name. |
| 144 resources: The list of resource names in grit_header. | 162 resources: The list of resource names in grit_header. |
| 145 filename: The file to scan. | 163 filename: The file to scan. |
| 146 | 164 |
| 147 Returns: | 165 Returns: |
| 148 True if the file should include the grit header. | 166 True if the file should include the grit header. |
| 149 """ | 167 """ |
| 150 # A list of special keywords that implies the file needs grit headers. | 168 # A list of special keywords that implies the file needs grit headers. |
| 151 # To be more thorough, one would need to run a pre-processor. | 169 # To be more thorough, one would need to run a pre-processor. |
| 152 SPECIAL_KEYWORDS = ( | 170 SPECIAL_KEYWORDS = ( |
| 153 'IMAGE_GRID(', # Macro in nine_image_painter_factory.h | |
| 154 '#include "ui_localizer_table.h"', # ui_localizer.mm | 171 '#include "ui_localizer_table.h"', # ui_localizer.mm |
| 155 'DEFINE_RESOURCE_ID', # chrome/browser/android/resource_mapper.cc | 172 'DEFINE_RESOURCE_ID', # chrome/browser/android/resource_mapper.cc |
| 156 ) | 173 ) |
| 157 with open(filename, 'rb') as f: | 174 with open(filename, 'rb') as f: |
| 158 grit_header_line = grit_header + '"\n' | 175 grit_header_line = grit_header + '"\n' |
| 159 has_grit_header = False | 176 has_grit_header = False |
| 160 while True: | 177 while True: |
| 161 line = f.readline() | 178 line = f.readline() |
| 162 if not line: | 179 if not line: |
| 163 break | 180 break |
| 164 if line.endswith(grit_header_line): | 181 if line.endswith(grit_header_line): |
| 165 has_grit_header = True | 182 has_grit_header = True |
| 166 break | 183 break |
| 167 | 184 |
| 168 if not has_grit_header: | 185 if not has_grit_header: |
| 169 return True | 186 return True |
| 170 rest_of_the_file = f.read() | 187 rest_of_the_file = f.read() |
| 171 return (any(resource in rest_of_the_file for resource in resources) or | 188 return (any(resource in rest_of_the_file for resource in resources) or |
| 172 any(keyword in rest_of_the_file for keyword in SPECIAL_KEYWORDS)) | 189 any(keyword in rest_of_the_file for keyword in SPECIAL_KEYWORDS)) |
| 173 | 190 |
| 174 | 191 |
| 175 def main(argv): | 192 def main(argv): |
| 176 if len(argv) < 3: | 193 if len(argv) < 3: |
| 177 Usage(argv[0]) | 194 Usage(argv[0]) |
| 178 return 1 | 195 return 1 |
| 179 grd_file = argv[1] | 196 grd_file = argv[1] |
| 180 dirs_to_scan = argv[2:] | 197 paths_to_scan = argv[2:] |
| 181 for f in dirs_to_scan: | 198 for f in paths_to_scan: |
| 182 if not os.path.exists(f): | 199 if not os.path.exists(f): |
| 183 print 'Error: %s does not exist' % f | 200 print 'Error: %s does not exist' % f |
| 184 return 1 | 201 return 1 |
| 185 | 202 |
| 186 tree = xml.etree.ElementTree.parse(grd_file) | 203 tree = xml.etree.ElementTree.parse(grd_file) |
| 187 grit_header = GetOutputHeaderFile(tree) | 204 grit_header = GetOutputHeaderFile(tree) |
| 188 if not grit_header: | 205 if not grit_header: |
| 189 print 'Error: %s does not generate any output headers.' % grit_header | 206 print 'Error: %s does not generate any output headers.' % grit_header |
| 190 return 1 | 207 return 1 |
| 191 resources = GetResourcesForGrdFile(tree, grd_file) | 208 resources = GetResourcesForGrdFile(tree, grd_file) |
| 192 | 209 |
| 193 files_with_unneeded_grit_includes = [] | 210 files_with_unneeded_grit_includes = [] |
| 194 for dir_to_scan in dirs_to_scan: | 211 for path_to_scan in paths_to_scan: |
| 195 for root, dirs, files in os.walk(dir_to_scan): | 212 if os.path.isdir(path_to_scan): |
| 196 if '.git' in dirs: | 213 for root, dirs, files in os.walk(path_to_scan): |
| 197 dirs.remove('.git') | 214 if '.git' in dirs: |
| 198 full_paths = [os.path.join(root, f) for f in files if ShouldScanFile(f)] | 215 dirs.remove('.git') |
| 199 files_with_unneeded_grit_includes.extend( | 216 full_paths = [os.path.join(root, f) for f in files if ShouldScanFile(f)] |
| 200 [f for f in full_paths | 217 files_with_unneeded_grit_includes.extend( |
| 201 if not NeedsGritInclude(grit_header, resources, f)]) | 218 [f for f in full_paths |
| 219 if not NeedsGritInclude(grit_header, resources, f)]) |
| 220 elif os.path.isfile(path_to_scan): |
| 221 if not NeedsGritInclude(grit_header, resources, path_to_scan): |
| 222 files_with_unneeded_grit_includes.append(path_to_scan) |
| 223 else: |
| 224 print 'Warning: Skipping %s' % path_to_scan |
| 225 |
| 202 if files_with_unneeded_grit_includes: | 226 if files_with_unneeded_grit_includes: |
| 203 print '\n'.join(files_with_unneeded_grit_includes) | 227 print '\n'.join(files_with_unneeded_grit_includes) |
| 204 return 2 | 228 return 2 |
| 205 return 0 | 229 return 0 |
| 206 | 230 |
| 207 | 231 |
| 208 if __name__ == '__main__': | 232 if __name__ == '__main__': |
| 209 sys.exit(main(sys.argv)) | 233 sys.exit(main(sys.argv)) |
| OLD | NEW |