"""Without any args, this simply loads the IDs out of a bunch of the Chrome GRD
files, and then checks the subset of the code that loads the strings to try
and figure out what isn't in use any more.
You can give paths to GRD files and source directories to control what is
check instead.
"""
from __future__ import print_function
import os
import re
import sys
import xml.sax
DEBUG = 0
class GrdIDExtractor(xml.sax.handler.ContentHandler):
"""Extracts the IDs from messages in GRIT files"""
def __init__(self):
self.id_set_ = set()
def startElement(self, name, attrs):
if name == 'message':
self.id_set_.add(attrs['name'])
def allIDs(self):
"""Return all the IDs found"""
return self.id_set_.copy()
def CheckForUnusedGrdIDsInSources(grd_files, src_dirs):
"""Will collect the message ids out of the given GRD files and then scan
the source directories to try and figure out what ids are not currently
being used by any source.
grd_files:
A list of GRD files to collect the ids from.
src_dirs:
A list of directories to walk looking for source files.
"""
all_ids = set()
file_id_map = {}
for y in grd_files:
handler = GrdIDExtractor()
xml.sax.parse(y, handler)
files_ids = handler.allIDs()
file_id_map[y] = files_ids
all_ids |= files_ids
id_regex = re.compile('IDS_[A-Z0-9_]+')
got_err = False
for x in all_ids:
match = id_regex.search(x)
if match is None:
print('ERROR: "%s" did not match our regex' % x)
got_err = True
if not match.group(0) is x:
print('ERROR: "%s" did not fully match our regex' % x)
got_err = True
if got_err:
return 1
src_regex = re.compile('\.(([chm])|(mm)|(cc)|(cp)|(cpp)|(xib)|(py))$')
ids_left = all_ids.copy()
for src_dir in src_dirs:
for root, dirs, files in os.walk(src_dir):
if '.svn' in dirs:
dirs.remove('.svn')
for file in files:
if src_regex.search(file.lower()):
full_path = os.path.join(root, file)
src_file_contents = open(full_path).read()
for match in sorted(set(id_regex.findall(src_file_contents))):
if match in ids_left:
ids_left.remove(match)
if DEBUG:
if not match in all_ids:
print('%s had "%s", which was not in the found IDs' % \
(full_path, match))
elif DEBUG > 1:
full_path = os.path.join(root, file)
print('Skipping %s.' % full_path)
if len(ids_left) > 0:
print('The following ids are in GRD files, but *appear* to be unused:')
for file_path, file_ids in file_id_map.iteritems():
missing = ids_left.intersection(file_ids)
if len(missing) > 0:
print(' %s:' % file_path)
print('\n'.join(' %s' % (x) for x in sorted(missing)))
return 0
def main():
tools_dir = os.path.dirname(os.path.abspath(sys.argv[0]))
src_dir = os.path.dirname(tools_dir)
src_dirs = []
grd_files = []
for arg in sys.argv[1:]:
if arg.lower().endswith('.grd') or arg.lower().endswith('.grdp'):
grd_files.append(arg)
else:
src_dirs.append(arg)
if len(grd_files) == 0:
ash_base_dir = os.path.join(src_dir, 'ash')
ash_shortcut_viewer_dir = os.path.join(ash_base_dir, 'shortcut_viewer')
chrome_dir = os.path.join(src_dir, 'chrome')
chrome_app_dir = os.path.join(chrome_dir, 'app')
chrome_app_res_dir = os.path.join(chrome_app_dir, 'resources')
device_base_dir = os.path.join(src_dir, 'device')
services_dir = os.path.join(src_dir, 'services')
ui_dir = os.path.join(src_dir, 'ui')
ui_strings_dir = os.path.join(ui_dir, 'strings')
ui_chromeos_dir = os.path.join(ui_dir, 'chromeos')
grd_files = [
os.path.join(ash_base_dir, 'ash_strings.grd'),
os.path.join(ash_shortcut_viewer_dir, 'shortcut_viewer_strings.grd'),
os.path.join(chrome_app_dir, 'chromium_strings.grd'),
os.path.join(chrome_app_dir, 'generated_resources.grd'),
os.path.join(chrome_app_dir, 'google_chrome_strings.grd'),
os.path.join(chrome_app_res_dir, 'locale_settings.grd'),
os.path.join(chrome_app_res_dir, 'locale_settings_chromiumos.grd'),
os.path.join(chrome_app_res_dir, 'locale_settings_google_chromeos.grd'),
os.path.join(chrome_app_res_dir, 'locale_settings_linux.grd'),
os.path.join(chrome_app_res_dir, 'locale_settings_mac.grd'),
os.path.join(chrome_app_res_dir, 'locale_settings_win.grd'),
os.path.join(chrome_app_dir, 'theme', 'theme_resources.grd'),
os.path.join(chrome_dir, 'browser', 'browser_resources.grd'),
os.path.join(chrome_dir, 'common', 'common_resources.grd'),
os.path.join(chrome_dir, 'renderer', 'resources',
'renderer_resources.grd'),
os.path.join(device_base_dir, 'bluetooth', 'bluetooth_strings.grd'),
os.path.join(device_base_dir, 'fido', 'fido_strings.grd'),
os.path.join(services_dir, 'services_strings.grd'),
os.path.join(src_dir, 'chromeos', 'chromeos_strings.grd'),
os.path.join(src_dir, 'extensions', 'strings',
'extensions_strings.grd'),
os.path.join(src_dir, 'ui', 'resources', 'ui_resources.grd'),
os.path.join(src_dir, 'ui', 'webui', 'resources',
'webui_resources.grd'),
os.path.join(ui_strings_dir, 'app_locale_settings.grd'),
os.path.join(ui_strings_dir, 'ax_strings.grd'),
os.path.join(ui_strings_dir, 'ui_strings.grd'),
os.path.join(ui_chromeos_dir, 'ui_chromeos_strings.grd'),
]
if len(src_dirs) == 0:
src_dirs = [
os.path.join(src_dir, 'app'),
os.path.join(src_dir, 'ash'),
os.path.join(src_dir, 'chrome'),
os.path.join(src_dir, 'components'),
os.path.join(src_dir, 'content'),
os.path.join(src_dir, 'device'),
os.path.join(src_dir, 'extensions'),
os.path.join(src_dir, 'ui'),
os.path.join(src_dir, 'third_party', 'mozilla_security_manager'),
os.path.join(chrome_dir, 'installer'),
]
return CheckForUnusedGrdIDsInSources(grd_files, src_dirs)
if __name__ == '__main__':
sys.exit(main())