2 # Copyright 2012 The Chromium Authors
3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file.
6 """Without any args, this simply loads the IDs out of a bunch of the Chrome GRD
7 files, and then checks the subset of the code that loads the strings to try
8 and figure out what isn't in use any more.
9 You can give paths to GRD files and source directories to control what is
13 from __future__ import print_function
20 # Extra messages along the way
21 # 1 - Print ids that are found in sources but not in the found id set
22 # 2 - Files that aren't processes (don't match the source name regex)
26 class GrdIDExtractor(xml.sax.handler.ContentHandler):
27 """Extracts the IDs from messages in GRIT files"""
31 def startElement(self, name, attrs):
33 self.id_set_.add(attrs['name'])
36 """Return all the IDs found"""
37 return self.id_set_.copy()
40 def CheckForUnusedGrdIDsInSources(grd_files, src_dirs):
41 """Will collect the message ids out of the given GRD files and then scan
42 the source directories to try and figure out what ids are not currently
43 being used by any source.
46 A list of GRD files to collect the ids from.
48 A list of directories to walk looking for source files.
50 # Collect all the ids into a large map
54 handler = GrdIDExtractor()
55 xml.sax.parse(y, handler)
56 files_ids = handler.allIDs()
57 file_id_map[y] = files_ids
61 # The regex that will be used to check sources
62 id_regex = re.compile('IDS_[A-Z0-9_]+')
64 # Make sure the regex matches every id found.
67 match = id_regex.search(x)
69 print('ERROR: "%s" did not match our regex' % x)
71 if not match.group(0) is x:
72 print('ERROR: "%s" did not fully match our regex' % x)
77 # The regex for deciding what is a source file
78 src_regex = re.compile('\.(([chm])|(mm)|(cc)|(cp)|(cpp)|(xib)|(py))$')
80 ids_left = all_ids.copy()
83 for src_dir in src_dirs:
84 for root, dirs, files in os.walk(src_dir):
85 # Remove svn directories from recursion
89 if src_regex.search(file.lower()):
90 full_path = os.path.join(root, file)
91 src_file_contents = open(full_path).read()
92 for match in sorted(set(id_regex.findall(src_file_contents))):
94 ids_left.remove(match)
96 if not match in all_ids:
97 print('%s had "%s", which was not in the found IDs' % \
100 full_path = os.path.join(root, file)
101 print('Skipping %s.' % full_path)
104 if len(ids_left) > 0:
105 print('The following ids are in GRD files, but *appear* to be unused:')
106 for file_path, file_ids in file_id_map.iteritems():
107 missing = ids_left.intersection(file_ids)
109 print(' %s:' % file_path)
110 print('\n'.join(' %s' % (x) for x in sorted(missing)))
116 # script lives in src/tools
117 tools_dir = os.path.dirname(os.path.abspath(sys.argv[0]))
118 src_dir = os.path.dirname(tools_dir)
120 # Collect the args into the right buckets
123 for arg in sys.argv[1:]:
124 if arg.lower().endswith('.grd') or arg.lower().endswith('.grdp'):
125 grd_files.append(arg)
129 # If no GRD files were given, default them:
130 if len(grd_files) == 0:
131 ash_base_dir = os.path.join(src_dir, 'ash')
132 ash_shortcut_viewer_dir = os.path.join(ash_base_dir, 'shortcut_viewer')
133 chrome_dir = os.path.join(src_dir, 'chrome')
134 chrome_app_dir = os.path.join(chrome_dir, 'app')
135 chrome_app_res_dir = os.path.join(chrome_app_dir, 'resources')
136 device_base_dir = os.path.join(src_dir, 'device')
137 services_dir = os.path.join(src_dir, 'services')
138 ui_dir = os.path.join(src_dir, 'ui')
139 ui_strings_dir = os.path.join(ui_dir, 'strings')
140 ui_chromeos_dir = os.path.join(ui_dir, 'chromeos')
142 os.path.join(ash_base_dir, 'ash_strings.grd'),
143 os.path.join(ash_shortcut_viewer_dir, 'shortcut_viewer_strings.grd'),
144 os.path.join(chrome_app_dir, 'chromium_strings.grd'),
145 os.path.join(chrome_app_dir, 'generated_resources.grd'),
146 os.path.join(chrome_app_dir, 'google_chrome_strings.grd'),
147 os.path.join(chrome_app_res_dir, 'locale_settings.grd'),
148 os.path.join(chrome_app_res_dir, 'locale_settings_chromiumos.grd'),
149 os.path.join(chrome_app_res_dir, 'locale_settings_google_chromeos.grd'),
150 os.path.join(chrome_app_res_dir, 'locale_settings_linux.grd'),
151 os.path.join(chrome_app_res_dir, 'locale_settings_mac.grd'),
152 os.path.join(chrome_app_res_dir, 'locale_settings_win.grd'),
153 os.path.join(chrome_app_dir, 'theme', 'theme_resources.grd'),
154 os.path.join(chrome_dir, 'browser', 'browser_resources.grd'),
155 os.path.join(chrome_dir, 'common', 'common_resources.grd'),
156 os.path.join(chrome_dir, 'renderer', 'resources',
157 'renderer_resources.grd'),
158 os.path.join(device_base_dir, 'bluetooth', 'bluetooth_strings.grd'),
159 os.path.join(device_base_dir, 'fido', 'fido_strings.grd'),
160 os.path.join(services_dir, 'services_strings.grd'),
161 os.path.join(src_dir, 'chromeos', 'chromeos_strings.grd'),
162 os.path.join(src_dir, 'extensions', 'strings',
163 'extensions_strings.grd'),
164 os.path.join(src_dir, 'ui', 'resources', 'ui_resources.grd'),
165 os.path.join(src_dir, 'ui', 'webui', 'resources',
166 'webui_resources.grd'),
167 os.path.join(ui_strings_dir, 'app_locale_settings.grd'),
168 os.path.join(ui_strings_dir, 'ax_strings.grd'),
169 os.path.join(ui_strings_dir, 'ui_strings.grd'),
170 os.path.join(ui_chromeos_dir, 'ui_chromeos_strings.grd'),
173 # If no source directories were given, default them:
174 if len(src_dirs) == 0:
176 os.path.join(src_dir, 'app'),
177 os.path.join(src_dir, 'ash'),
178 os.path.join(src_dir, 'chrome'),
179 os.path.join(src_dir, 'components'),
180 os.path.join(src_dir, 'content'),
181 os.path.join(src_dir, 'device'),
182 os.path.join(src_dir, 'extensions'),
183 os.path.join(src_dir, 'ui'),
184 # nsNSSCertHelper.cpp has a bunch of ids
185 os.path.join(src_dir, 'third_party', 'mozilla_security_manager'),
186 os.path.join(chrome_dir, 'installer'),
189 return CheckForUnusedGrdIDsInSources(grd_files, src_dirs)
192 if __name__ == '__main__':