[email protected] | 2fac375 | 2011-11-27 20:56:51 | [diff] [blame] | 1 | #!/usr/bin/env python |
[email protected] | 2b1fbb9d | 2012-02-08 07:30:51 | [diff] [blame] | 2 | # Copyright (c) 2012 The Chromium Authors. All rights reserved. |
[email protected] | f16943a1 | 2010-04-09 13:07:19 | [diff] [blame] | 3 | # 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 |
| 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 |
| 10 | check instead. |
| 11 | """ |
| 12 | |
Raul Tambre | 4cec3657 | 2019-09-22 17:30:32 | [diff] [blame] | 13 | from __future__ import print_function |
| 14 | |
[email protected] | f16943a1 | 2010-04-09 13:07:19 | [diff] [blame] | 15 | import os |
| 16 | import re |
| 17 | import sys |
| 18 | import 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) |
| 23 | DEBUG = 0 |
| 24 | |
| 25 | |
| 26 | class 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 | |
| 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. |
| 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 Tambre | 4cec3657 | 2019-09-22 17:30:32 | [diff] [blame] | 69 | print('ERROR: "%s" did not match our regex' % x) |
[email protected] | f16943a1 | 2010-04-09 13:07:19 | [diff] [blame] | 70 | got_err = True |
| 71 | if not match.group(0) is x: |
Raul Tambre | 4cec3657 | 2019-09-22 17:30:32 | [diff] [blame] | 72 | print('ERROR: "%s" did not fully match our regex' % x) |
[email protected] | f16943a1 | 2010-04-09 13:07:19 | [diff] [blame] | 73 | got_err = True |
| 74 | if got_err: |
| 75 | return 1 |
| 76 | |
| 77 | # The regex for deciding what is a source file |
[email protected] | cf83d25 | 2011-11-30 00:20:21 | [diff] [blame] | 78 | src_regex = re.compile('\.(([chm])|(mm)|(cc)|(cp)|(cpp)|(xib)|(py))$') |
[email protected] | f16943a1 | 2010-04-09 13:07:19 | [diff] [blame] | 79 | |
| 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 Tambre | 4cec3657 | 2019-09-22 17:30:32 | [diff] [blame] | 97 | print('%s had "%s", which was not in the found IDs' % \ |
| 98 | (full_path, match)) |
[email protected] | f16943a1 | 2010-04-09 13:07:19 | [diff] [blame] | 99 | elif DEBUG > 1: |
| 100 | full_path = os.path.join(root, file) |
Raul Tambre | 4cec3657 | 2019-09-22 17:30:32 | [diff] [blame] | 101 | print('Skipping %s.' % full_path) |
[email protected] | f16943a1 | 2010-04-09 13:07:19 | [diff] [blame] | 102 | |
| 103 | # Anything left? |
| 104 | if len(ids_left) > 0: |
Raul Tambre | 4cec3657 | 2019-09-22 17:30:32 | [diff] [blame] | 105 | print('The following ids are in GRD files, but *appear* to be unused:') |
[email protected] | f16943a1 | 2010-04-09 13:07:19 | [diff] [blame] | 106 | for file_path, file_ids in file_id_map.iteritems(): |
| 107 | missing = ids_left.intersection(file_ids) |
| 108 | if len(missing) > 0: |
Raul Tambre | 4cec3657 | 2019-09-22 17:30:32 | [diff] [blame] | 109 | print(' %s:' % file_path) |
| 110 | print('\n'.join(' %s' % (x) for x in sorted(missing))) |
[email protected] | f16943a1 | 2010-04-09 13:07:19 | [diff] [blame] | 111 | |
| 112 | return 0 |
| 113 | |
| 114 | |
[email protected] | 2fac375 | 2011-11-27 20:56:51 | [diff] [blame] | 115 | def main(): |
tfarina | c9fc190 | 2014-08-29 16:19:04 | [diff] [blame] | 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) |
[email protected] | f16943a1 | 2010-04-09 13:07:19 | [diff] [blame] | 119 | |
| 120 | # Collect the args into the right buckets |
| 121 | src_dirs = [] |
| 122 | grd_files = [] |
| 123 | for arg in sys.argv[1:]: |
Steven Bennetts | 528eec5 | 2017-11-10 19:21:19 | [diff] [blame] | 124 | if arg.lower().endswith('.grd') or arg.lower().endswith('.grdp'): |
[email protected] | f16943a1 | 2010-04-09 13:07:19 | [diff] [blame] | 125 | 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] | 2b1fbb9d | 2012-02-08 07:30:51 | [diff] [blame] | 131 | ash_base_dir = os.path.join(src_dir, 'ash') |
Mitsuru Oshima | e5af41e6 | 2020-03-11 22:17:00 | [diff] [blame] | 132 | ash_shortcut_viewer_dir = os.path.join(ash_base_dir, 'shortcut_viewer') |
tfarina | c9fc190 | 2014-08-29 16:19:04 | [diff] [blame] | 133 | chrome_dir = os.path.join(src_dir, 'chrome') |
[email protected] | f16943a1 | 2010-04-09 13:07:19 | [diff] [blame] | 134 | chrome_app_dir = os.path.join(chrome_dir, 'app') |
| 135 | chrome_app_res_dir = os.path.join(chrome_app_dir, 'resources') |
[email protected] | 8a92bbd | 2013-02-22 01:07:29 | [diff] [blame] | 136 | device_base_dir = os.path.join(src_dir, 'device') |
Ken Rockot | cebdf9c8 | 2019-05-28 20:33:03 | [diff] [blame] | 137 | services_dir = os.path.join(src_dir, 'services') |
[email protected] | 0204084 | 2014-08-21 04:29:10 | [diff] [blame] | 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') |
[email protected] | f16943a1 | 2010-04-09 13:07:19 | [diff] [blame] | 141 | grd_files = [ |
[email protected] | 2b1fbb9d | 2012-02-08 07:30:51 | [diff] [blame] | 142 | os.path.join(ash_base_dir, 'ash_strings.grd'), |
Mitsuru Oshima | 501b6f7e | 2020-06-09 03:51:18 | [diff] [blame] | 143 | os.path.join(ash_shortcut_viewer_dir, 'shortcut_viewer_strings.grd'), |
[email protected] | f16943a1 | 2010-04-09 13:07:19 | [diff] [blame] | 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'), |
[email protected] | 80b1adf | 2012-11-17 14:20:11 | [diff] [blame] | 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'), |
[email protected] | f16943a1 | 2010-04-09 13:07:19 | [diff] [blame] | 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'), |
[email protected] | 8d0d4f7d | 2012-09-11 03:31:29 | [diff] [blame] | 156 | os.path.join(chrome_dir, 'renderer', 'resources', |
| 157 | 'renderer_resources.grd'), |
[email protected] | e3a9ccfc | 2013-06-03 00:22:30 | [diff] [blame] | 158 | os.path.join(device_base_dir, 'bluetooth', 'bluetooth_strings.grd'), |
Martin Kreichgauer | 2d30db4 | 2018-08-13 18:02:31 | [diff] [blame] | 159 | os.path.join(device_base_dir, 'fido', 'fido_strings.grd'), |
Raul Tambre | 4cec3657 | 2019-09-22 17:30:32 | [diff] [blame] | 160 | os.path.join(services_dir, 'services_strings.grd'), |
Li Lin | c5838fe | 2018-08-28 22:52:13 | [diff] [blame] | 161 | os.path.join(src_dir, 'chromeos', 'chromeos_strings.grd'), |
jamescook | 488cf9d | 2017-04-06 19:39:35 | [diff] [blame] | 162 | os.path.join(src_dir, 'extensions', 'strings', 'extensions_strings.grd'), |
[email protected] | 29b25d09 | 2011-06-29 20:57:34 | [diff] [blame] | 163 | os.path.join(src_dir, 'ui', 'resources', 'ui_resources.grd'), |
[email protected] | 70fd3bb | 2013-02-28 08:55:04 | [diff] [blame] | 164 | os.path.join(src_dir, 'ui', 'webui', 'resources', 'webui_resources.grd'), |
[email protected] | 0204084 | 2014-08-21 04:29:10 | [diff] [blame] | 165 | os.path.join(ui_strings_dir, 'app_locale_settings.grd'), |
| 166 | os.path.join(ui_strings_dir, 'ui_strings.grd'), |
[email protected] | ece882c8 | 2014-07-13 04:03:42 | [diff] [blame] | 167 | os.path.join(ui_chromeos_dir, 'ui_chromeos_strings.grd'), |
[email protected] | f16943a1 | 2010-04-09 13:07:19 | [diff] [blame] | 168 | ] |
| 169 | |
| 170 | # If no source directories were given, default them: |
| 171 | if len(src_dirs) == 0: |
| 172 | src_dirs = [ |
| 173 | os.path.join(src_dir, 'app'), |
[email protected] | 3923c13 | 2012-08-22 16:45:54 | [diff] [blame] | 174 | os.path.join(src_dir, 'ash'), |
[email protected] | f16943a1 | 2010-04-09 13:07:19 | [diff] [blame] | 175 | os.path.join(src_dir, 'chrome'), |
[email protected] | 79c24cd | 2013-03-12 04:37:37 | [diff] [blame] | 176 | os.path.join(src_dir, 'components'), |
[email protected] | cf83d25 | 2011-11-30 00:20:21 | [diff] [blame] | 177 | os.path.join(src_dir, 'content'), |
[email protected] | 050ed684 | 2013-03-04 20:18:18 | [diff] [blame] | 178 | os.path.join(src_dir, 'device'), |
[email protected] | 99c0125b | 2014-04-17 05:21:57 | [diff] [blame] | 179 | os.path.join(src_dir, 'extensions'), |
[email protected] | 4c9101d | 2011-03-15 20:49:48 | [diff] [blame] | 180 | os.path.join(src_dir, 'ui'), |
[email protected] | f16943a1 | 2010-04-09 13:07:19 | [diff] [blame] | 181 | # nsNSSCertHelper.cpp has a bunch of ids |
| 182 | os.path.join(src_dir, 'third_party', 'mozilla_security_manager'), |
[email protected] | cf83d25 | 2011-11-30 00:20:21 | [diff] [blame] | 183 | os.path.join(chrome_dir, 'installer'), |
[email protected] | f16943a1 | 2010-04-09 13:07:19 | [diff] [blame] | 184 | ] |
| 185 | |
[email protected] | 2fac375 | 2011-11-27 20:56:51 | [diff] [blame] | 186 | return CheckForUnusedGrdIDsInSources(grd_files, src_dirs) |
| 187 | |
| 188 | |
| 189 | if __name__ == '__main__': |
| 190 | sys.exit(main()) |