blob: 4924fe51f90c74387397ed582a656ff552552483 [file] [log] [blame]
[email protected]2fac3752011-11-27 20:56:511#!/usr/bin/env python
[email protected]2b1fbb9d2012-02-08 07:30:512# Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]f16943a12010-04-09 13:07:193# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5
6"""Without any args, this simply loads the IDs out of a bunch of the Chrome GRD
7files, and then checks the subset of the code that loads the strings to try
8and figure out what isn't in use any more.
9You can give paths to GRD files and source directories to control what is
10check instead.
11"""
12
Raul Tambre4cec36572019-09-22 17:30:3213from __future__ import print_function
14
[email protected]f16943a12010-04-09 13:07:1915import os
16import re
17import sys
18import xml.sax
19
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)
23DEBUG = 0
24
25
26class GrdIDExtractor(xml.sax.handler.ContentHandler):
27 """Extracts the IDs from messages in GRIT files"""
28 def __init__(self):
29 self.id_set_ = set()
30
31 def startElement(self, name, attrs):
32 if name == 'message':
33 self.id_set_.add(attrs['name'])
34
35 def allIDs(self):
36 """Return all the IDs found"""
37 return self.id_set_.copy()
38
39
40def 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.
44
45 grd_files:
46 A list of GRD files to collect the ids from.
47 src_dirs:
48 A list of directories to walk looking for source files.
49 """
50 # Collect all the ids into a large map
51 all_ids = set()
52 file_id_map = {}
53 for y in grd_files:
54 handler = GrdIDExtractor()
55 xml.sax.parse(y, handler)
56 files_ids = handler.allIDs()
57 file_id_map[y] = files_ids
58 all_ids |= files_ids
59
60
61 # The regex that will be used to check sources
62 id_regex = re.compile('IDS_[A-Z0-9_]+')
63
64 # Make sure the regex matches every id found.
65 got_err = False
66 for x in all_ids:
67 match = id_regex.search(x)
68 if match is None:
Raul Tambre4cec36572019-09-22 17:30:3269 print('ERROR: "%s" did not match our regex' % x)
[email protected]f16943a12010-04-09 13:07:1970 got_err = True
71 if not match.group(0) is x:
Raul Tambre4cec36572019-09-22 17:30:3272 print('ERROR: "%s" did not fully match our regex' % x)
[email protected]f16943a12010-04-09 13:07:1973 got_err = True
74 if got_err:
75 return 1
76
77 # The regex for deciding what is a source file
[email protected]cf83d252011-11-30 00:20:2178 src_regex = re.compile('\.(([chm])|(mm)|(cc)|(cp)|(cpp)|(xib)|(py))$')
[email protected]f16943a12010-04-09 13:07:1979
80 ids_left = all_ids.copy()
81
82 # Scanning time.
83 for src_dir in src_dirs:
84 for root, dirs, files in os.walk(src_dir):
85 # Remove svn directories from recursion
86 if '.svn' in dirs:
87 dirs.remove('.svn')
88 for file in files:
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))):
93 if match in ids_left:
94 ids_left.remove(match)
95 if DEBUG:
96 if not match in all_ids:
Raul Tambre4cec36572019-09-22 17:30:3297 print('%s had "%s", which was not in the found IDs' % \
98 (full_path, match))
[email protected]f16943a12010-04-09 13:07:1999 elif DEBUG > 1:
100 full_path = os.path.join(root, file)
Raul Tambre4cec36572019-09-22 17:30:32101 print('Skipping %s.' % full_path)
[email protected]f16943a12010-04-09 13:07:19102
103 # Anything left?
104 if len(ids_left) > 0:
Raul Tambre4cec36572019-09-22 17:30:32105 print('The following ids are in GRD files, but *appear* to be unused:')
[email protected]f16943a12010-04-09 13:07:19106 for file_path, file_ids in file_id_map.iteritems():
107 missing = ids_left.intersection(file_ids)
108 if len(missing) > 0:
Raul Tambre4cec36572019-09-22 17:30:32109 print(' %s:' % file_path)
110 print('\n'.join(' %s' % (x) for x in sorted(missing)))
[email protected]f16943a12010-04-09 13:07:19111
112 return 0
113
114
[email protected]2fac3752011-11-27 20:56:51115def main():
tfarinac9fc1902014-08-29 16:19:04116 # 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)
[email protected]f16943a12010-04-09 13:07:19119
120 # Collect the args into the right buckets
121 src_dirs = []
122 grd_files = []
123 for arg in sys.argv[1:]:
Steven Bennetts528eec52017-11-10 19:21:19124 if arg.lower().endswith('.grd') or arg.lower().endswith('.grdp'):
[email protected]f16943a12010-04-09 13:07:19125 grd_files.append(arg)
126 else:
127 src_dirs.append(arg)
128
129 # If no GRD files were given, default them:
130 if len(grd_files) == 0:
[email protected]2b1fbb9d2012-02-08 07:30:51131 ash_base_dir = os.path.join(src_dir, 'ash')
wutaocd13722f2018-02-21 22:00:35132 ash_components_dir = os.path.join(ash_base_dir, 'components')
tfarinac9fc1902014-08-29 16:19:04133 chrome_dir = os.path.join(src_dir, 'chrome')
[email protected]f16943a12010-04-09 13:07:19134 chrome_app_dir = os.path.join(chrome_dir, 'app')
135 chrome_app_res_dir = os.path.join(chrome_app_dir, 'resources')
[email protected]8a92bbd2013-02-22 01:07:29136 device_base_dir = os.path.join(src_dir, 'device')
Ken Rockotcebdf9c82019-05-28 20:33:03137 services_dir = os.path.join(src_dir, 'services')
[email protected]02040842014-08-21 04:29:10138 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')
[email protected]f16943a12010-04-09 13:07:19141 grd_files = [
[email protected]2b1fbb9d2012-02-08 07:30:51142 os.path.join(ash_base_dir, 'ash_strings.grd'),
wutaocd13722f2018-02-21 22:00:35143 os.path.join(ash_components_dir, 'ash_components_strings.grd'),
144 os.path.join(ash_components_dir, 'resources',
145 'ash_components_resources.grd'),
[email protected]f16943a12010-04-09 13:07:19146 os.path.join(chrome_app_dir, 'chromium_strings.grd'),
147 os.path.join(chrome_app_dir, 'generated_resources.grd'),
148 os.path.join(chrome_app_dir, 'google_chrome_strings.grd'),
149 os.path.join(chrome_app_res_dir, 'locale_settings.grd'),
[email protected]80b1adf2012-11-17 14:20:11150 os.path.join(chrome_app_res_dir, 'locale_settings_chromiumos.grd'),
151 os.path.join(chrome_app_res_dir, 'locale_settings_google_chromeos.grd'),
[email protected]f16943a12010-04-09 13:07:19152 os.path.join(chrome_app_res_dir, 'locale_settings_linux.grd'),
153 os.path.join(chrome_app_res_dir, 'locale_settings_mac.grd'),
154 os.path.join(chrome_app_res_dir, 'locale_settings_win.grd'),
155 os.path.join(chrome_app_dir, 'theme', 'theme_resources.grd'),
156 os.path.join(chrome_dir, 'browser', 'browser_resources.grd'),
157 os.path.join(chrome_dir, 'common', 'common_resources.grd'),
[email protected]8d0d4f7d2012-09-11 03:31:29158 os.path.join(chrome_dir, 'renderer', 'resources',
159 'renderer_resources.grd'),
[email protected]e3a9ccfc2013-06-03 00:22:30160 os.path.join(device_base_dir, 'bluetooth', 'bluetooth_strings.grd'),
Martin Kreichgauer2d30db42018-08-13 18:02:31161 os.path.join(device_base_dir, 'fido', 'fido_strings.grd'),
Raul Tambre4cec36572019-09-22 17:30:32162 os.path.join(services_dir, 'services_strings.grd'),
Li Linc5838fe2018-08-28 22:52:13163 os.path.join(src_dir, 'chromeos', 'chromeos_strings.grd'),
jamescook488cf9d2017-04-06 19:39:35164 os.path.join(src_dir, 'extensions', 'strings', 'extensions_strings.grd'),
[email protected]29b25d092011-06-29 20:57:34165 os.path.join(src_dir, 'ui', 'resources', 'ui_resources.grd'),
[email protected]70fd3bb2013-02-28 08:55:04166 os.path.join(src_dir, 'ui', 'webui', 'resources', 'webui_resources.grd'),
[email protected]02040842014-08-21 04:29:10167 os.path.join(ui_strings_dir, 'app_locale_settings.grd'),
168 os.path.join(ui_strings_dir, 'ui_strings.grd'),
[email protected]ece882c82014-07-13 04:03:42169 os.path.join(ui_chromeos_dir, 'ui_chromeos_strings.grd'),
[email protected]f16943a12010-04-09 13:07:19170 ]
171
172 # If no source directories were given, default them:
173 if len(src_dirs) == 0:
174 src_dirs = [
175 os.path.join(src_dir, 'app'),
[email protected]3923c132012-08-22 16:45:54176 os.path.join(src_dir, 'ash'),
[email protected]f16943a12010-04-09 13:07:19177 os.path.join(src_dir, 'chrome'),
[email protected]79c24cd2013-03-12 04:37:37178 os.path.join(src_dir, 'components'),
[email protected]cf83d252011-11-30 00:20:21179 os.path.join(src_dir, 'content'),
[email protected]050ed6842013-03-04 20:18:18180 os.path.join(src_dir, 'device'),
[email protected]99c0125b2014-04-17 05:21:57181 os.path.join(src_dir, 'extensions'),
[email protected]4c9101d2011-03-15 20:49:48182 os.path.join(src_dir, 'ui'),
[email protected]f16943a12010-04-09 13:07:19183 # nsNSSCertHelper.cpp has a bunch of ids
184 os.path.join(src_dir, 'third_party', 'mozilla_security_manager'),
[email protected]cf83d252011-11-30 00:20:21185 os.path.join(chrome_dir, 'installer'),
[email protected]f16943a12010-04-09 13:07:19186 ]
187
[email protected]2fac3752011-11-27 20:56:51188 return CheckForUnusedGrdIDsInSources(grd_files, src_dirs)
189
190
191if __name__ == '__main__':
192 sys.exit(main())