Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(46)

Side by Side Diff: tools/unused-grit-header.py

Issue 504503002: Add a tool to look for source files that have unneeded grit header includes. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 6 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 #!/usr/bin/env python
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
4 # found in the LICENSE file.
5
6 """A tool to scan source files for unneeded grit includes."""
Nico 2014/08/24 23:58:25 Include a usage line
Lei Zhang 2014/08/26 02:35:24 Usage() is literally 6 lines below...
7
8 import os
9 import sys
10 import xml.etree.ElementTree
11
Nico 2014/08/24 23:58:26 2 empty lines between toplevels
Lei Zhang 2014/08/26 02:35:25 Done.
12 def Usage(prog_name):
13 print prog_name, 'GRD_FILE DIRS_TO_SCAN'
Nico 2014/08/24 23:58:25 Consider using optparse or argparse (see e.g. tool
Lei Zhang 2014/08/26 02:35:24 There's no options. If we do add options later, I'
Nico 2014/08/26 02:43:37 It also offers usage printing (you can hand it the
14
15
16 def GetResourcesForNode(node, parent_file, resource_tag):
17 """Recursively iterate through a node and extract resource names.
18
19 Args:
20 node: The node to iterate through.
21 parent_file: The file that contains node.
22 resource_tag: The resource tag to extract names from.
23
24 Returns:
25 A list of resource names.
26 """
27 resources = []
28 for child in node.getchildren():
29 if child.tag == resource_tag:
30 resources.append(child.attrib['name'])
31 elif child.tag == 'if':
32 resources.extend(GetResourcesForNode(child, parent_file, resource_tag))
33 elif child.tag == 'part':
34 parent_dir = os.path.dirname(parent_file)
35 part_file = os.path.join(parent_dir, child.attrib['file'])
36 part_tree = xml.etree.ElementTree.parse(part_file)
37 part_root = part_tree.getroot()
38 assert part_root.tag == 'grit-part'
39 resources.extend(GetResourcesForNode(part_root, part_file, resource_tag))
40 else:
41 raise Exception('unknown tag:', child.tag)
42 return resources
43
44
45 def GetResourcesForGrdFile(tree, grd_file):
46 """Find all the message and include resources from a given grit file.
47
48 Args:
49 tree: The XML tree.
50 grd_file: The file that contains the XML tree.
51
52 Returns:
53 A list of resource names.
54 """
55 root = tree.getroot()
56 assert root.tag == 'grit'
57 for node in root.getchildren():
58 if node.tag == 'release':
59 release_node = node
60 break
61 assert release_node != None
62
63 for node in release_node.getchildren():
64 if node.tag == 'messages':
65 messages_node = node
66 break
67 messages = set()
68 if messages_node != None:
69 messages = set(GetResourcesForNode(messages_node, grd_file, 'message'))
70
71 for node in release_node.getchildren():
72 if node.tag == 'includes':
73 includes_node = node
74 break
Nico 2014/08/24 23:58:25 Since you have this for loop 3 times, consider hav
Lei Zhang 2014/08/26 02:35:24 Done.
75 includes = set()
76 if includes_node != None:
77 includes = set(GetResourcesForNode(includes_node, grd_file, 'include'))
78 return messages.union(includes)
79
80
81 def GetOutputFileForNode(node):
82 """Find the output file starting from a given node.
83
84 Args:
85 node: The root node to scan from.
86
87 Returns:
88 A grit header file name.
89 """
90 output_file = None
91 for child in node.getchildren():
92 if child.tag == 'output':
93 if child.attrib['type'] == 'rc_header':
94 assert output_file == None
95 output_file = child.attrib['filename']
96 elif child.tag == 'if':
Nico 2014/08/24 23:58:26 do you need to look at 'else' children of if nodes
Lei Zhang 2014/08/26 02:35:25 I don't think grit has <else> nodes? It may be pos
Nico 2014/08/26 02:43:37 see https://codereview.chromium.org/11155024
97 child_output_file = GetOutputFileForNode(child)
98 if not child_output_file:
99 continue
100 assert output_file == None
Nico 2014/08/24 23:58:25 nit: it's more common to see "output_file is None"
Lei Zhang 2014/08/26 02:35:25 Done.
101 output_file = child_output_file
102 else:
103 raise Exception('unknown tag:', child.tag)
104 return output_file
105
106
107 def GetOutputHeaderFile(tree):
108 """Find the output file for a given tree.
109
110 Args:
111 tree: The tree to scan.
112
113 Returns:
114 A grit header file name.
115 """
116 root = tree.getroot()
117 assert root.tag == 'grit'
118 for node in root.getchildren():
119 if node.tag == 'outputs':
120 output_node = node
121 break
Nico 2014/08/24 23:58:26 Maybe `assert not output_node` before the assignme
Lei Zhang 2014/08/26 02:35:24 Done. And elsewhere above.
122 assert output_node != None
123 return GetOutputFileForNode(output_node)
124
125
126 def ShouldScanFile(filename):
127 """Return if the filename has one of the extensions below."""
128 extensions = ['.cc', '.cpp', '.h', '.mm']
129 file_extension = os.path.splitext(filename)[1]
130 return file_extension in extensions
131
Nico 2014/08/24 23:58:26 add a newline
Lei Zhang 2014/08/26 02:35:24 Done.
132 def NeedsGritInclude(grit_header, resources, filename):
133 """Return whether a file needs a given grit header or not.
134
135 Args:
136 grit_header: The grit header file name.
137 resources: The list of resource names in grit_header.
138 filename: The file to scan.
139
140 Returns:
141 True if the file should include the grit header.
142 """
143 with open(filename, 'rb') as f:
144 grit_header_line = grit_header + '"\n'
145 has_grit_header = False
146 while True:
147 line = f.readline()
148 if not line:
149 break
150 if line.endswith(grit_header_line):
151 has_grit_header = True
152 break
153
154 if not has_grit_header:
155 return True
156 rest_of_the_file = f.read()
157 return any(resource in rest_of_the_file for resource in resources)
158
159
160 def main(argv):
161 if len(argv) < 3:
162 Usage(argv[0])
163 sys.exit(1)
164 grd_file = argv[1]
165 dirs_to_scan = argv[2:]
166 for f in dirs_to_scan:
167 if not os.path.exists(f):
168 print 'Error: %s does not exist' % f
169 sys.exit(1)
170
171 tree = xml.etree.ElementTree.parse(grd_file)
172 grit_header = GetOutputHeaderFile(tree)
173 resources = GetResourcesForGrdFile(tree, grd_file)
174
175 files_with_unneeded_grit_includes = []
176 for dir_to_scan in dirs_to_scan:
177 for root, dirs, files in os.walk(dir_to_scan):
178 if '.git' in dirs:
179 dirs.remove('.git')
180 full_paths = [os.path.join(root, f) for f in files if ShouldScanFile(f)]
181 files_with_unneeded_grit_includes.extend(
182 [f for f in full_paths
183 if not NeedsGritInclude(grit_header, resources, f)])
184 if files_with_unneeded_grit_includes:
185 print '\n'.join(files_with_unneeded_grit_includes)
186 sys.exit(2)
187 sys.exit(0)
188
Nico 2014/08/24 23:58:25 add newline
Lei Zhang 2014/08/26 02:35:24 Done.
189 if __name__ == '__main__':
190 main(sys.argv)
Nico 2014/08/24 23:58:25 nit: the usual thing is `sys.exit(main(sys.argv))
Lei Zhang 2014/08/26 02:35:24 Done.
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698