diff options
author | tfarina <tfarina@chromium.org> | 2014-08-29 09:19:04 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2014-08-29 16:20:30 +0000 |
commit | c9fc190dc2c26f6bea35ff8cf33e209d04e7b41c (patch) | |
tree | d393d6692d91001d09f2bd9a38cb9b02362f5bf5 /tools/check_grd_for_unused_strings.py | |
parent | a7703f15c24dfbd4418cb051c4c7547102312d3f (diff) | |
download | chromium_src-c9fc190dc2c26f6bea35ff8cf33e209d04e7b41c.zip chromium_src-c9fc190dc2c26f6bea35ff8cf33e209d04e7b41c.tar.gz chromium_src-c9fc190dc2c26f6bea35ff8cf33e209d04e7b41c.tar.bz2 |
Cleanup: Move check_grd_for_unused_strings.py out of chrome/
It isn't specific to chrome, it has a broader usage.
BUG=None
TEST=./tools/check_grd_for_unused_strings.py
R=thestig@chromium.org
Review URL: https://codereview.chromium.org/523523002
Cr-Commit-Position: refs/heads/master@{#292646}
Diffstat (limited to 'tools/check_grd_for_unused_strings.py')
-rwxr-xr-x | tools/check_grd_for_unused_strings.py | 183 |
1 files changed, 183 insertions, 0 deletions
diff --git a/tools/check_grd_for_unused_strings.py b/tools/check_grd_for_unused_strings.py new file mode 100755 index 0000000..8124b57 --- /dev/null +++ b/tools/check_grd_for_unused_strings.py @@ -0,0 +1,183 @@ +#!/usr/bin/env python +# Copyright (c) 2012 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +"""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. +""" + +import os +import re +import sys +import xml.sax + +# Extra messages along the way +# 1 - Print ids that are found in sources but not in the found id set +# 2 - Files that aren't processes (don't match the source name regex) +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. + """ + # Collect all the ids into a large map + 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 + + + # The regex that will be used to check sources + id_regex = re.compile('IDS_[A-Z0-9_]+') + + # Make sure the regex matches every id found. + 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 + + # The regex for deciding what is a source file + src_regex = re.compile('\.(([chm])|(mm)|(cc)|(cp)|(cpp)|(xib)|(py))$') + + ids_left = all_ids.copy() + + # Scanning time. + for src_dir in src_dirs: + for root, dirs, files in os.walk(src_dir): + # Remove svn directories from recursion + 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) + + # Anything left? + 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(): + # script lives in src/tools + tools_dir = os.path.dirname(os.path.abspath(sys.argv[0])) + src_dir = os.path.dirname(tools_dir) + + # Collect the args into the right buckets + src_dirs = [] + grd_files = [] + for arg in sys.argv[1:]: + if arg.lower().endswith('.grd'): + grd_files.append(arg) + else: + src_dirs.append(arg) + + # If no GRD files were given, default them: + if len(grd_files) == 0: + ash_base_dir = os.path.join(src_dir, 'ash') + 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') + 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_base_dir, 'resources', 'ash_resources.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(src_dir, 'extensions', '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, 'ui_strings.grd'), + os.path.join(ui_chromeos_dir, 'ui_chromeos_strings.grd'), + ] + + # If no source directories were given, default them: + 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'), + # nsNSSCertHelper.cpp has a bunch of ids + 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()) |