15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#!/usr/bin/env python 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Copyright (c) 2012 The Chromium Authors. All rights reserved. 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Use of this source code is governed by a BSD-style license that can be 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# found in the LICENSE file. 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)"""Without any args, this simply loads the IDs out of a bunch of the Chrome GRD 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)files, and then checks the subset of the code that loads the strings to try 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)and figure out what isn't in use any more. 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)You can give paths to GRD files and source directories to control what is 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)check instead. 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)""" 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import os 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import re 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import sys 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import xml.sax 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Extra messages along the way 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# 1 - Print ids that are found in sources but not in the found id set 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# 2 - Files that aren't processes (don't match the source name regex) 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DEBUG = 0 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class GrdIDExtractor(xml.sax.handler.ContentHandler): 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Extracts the IDs from messages in GRIT files""" 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def __init__(self): 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.id_set_ = set() 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def startElement(self, name, attrs): 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if name == 'message': 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.id_set_.add(attrs['name']) 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def allIDs(self): 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Return all the IDs found""" 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return self.id_set_.copy() 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def CheckForUnusedGrdIDsInSources(grd_files, src_dirs): 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Will collect the message ids out of the given GRD files and then scan 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) the source directories to try and figure out what ids are not currently 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) being used by any source. 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) grd_files: 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) A list of GRD files to collect the ids from. 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) src_dirs: 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) A list of directories to walk looking for source files. 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Collect all the ids into a large map 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) all_ids = set() 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) file_id_map = {} 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for y in grd_files: 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) handler = GrdIDExtractor() 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) xml.sax.parse(y, handler) 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) files_ids = handler.allIDs() 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) file_id_map[y] = files_ids 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) all_ids |= files_ids 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # The regex that will be used to check sources 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) id_regex = re.compile('IDS_[A-Z0-9_]+') 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Make sure the regex matches every id found. 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) got_err = False 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for x in all_ids: 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) match = id_regex.search(x) 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if match is None: 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) print 'ERROR: "%s" did not match our regex' % (x) 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) got_err = True 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not match.group(0) is x: 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) print 'ERROR: "%s" did not fully match our regex' % (x) 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) got_err = True 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if got_err: 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 1 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # The regex for deciding what is a source file 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) src_regex = re.compile('\.(([chm])|(mm)|(cc)|(cp)|(cpp)|(xib)|(py))$') 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ids_left = all_ids.copy() 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Scanning time. 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for src_dir in src_dirs: 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for root, dirs, files in os.walk(src_dir): 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Remove svn directories from recursion 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if '.svn' in dirs: 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dirs.remove('.svn') 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for file in files: 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if src_regex.search(file.lower()): 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) full_path = os.path.join(root, file) 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) src_file_contents = open(full_path).read() 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for match in sorted(set(id_regex.findall(src_file_contents))): 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if match in ids_left: 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ids_left.remove(match) 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if DEBUG: 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not match in all_ids: 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) print '%s had "%s", which was not in the found IDs' % \ 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (full_path, match) 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) elif DEBUG > 1: 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) full_path = os.path.join(root, file) 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) print 'Skipping %s.' % (full_path) 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Anything left? 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if len(ids_left) > 0: 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) print 'The following ids are in GRD files, but *appear* to be unused:' 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for file_path, file_ids in file_id_map.iteritems(): 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) missing = ids_left.intersection(file_ids) 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if len(missing) > 0: 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) print ' %s:' % (file_path) 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) print '\n'.join(' %s' % (x) for x in sorted(missing)) 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def main(): 1141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci # script lives in src/tools 1151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci tools_dir = os.path.dirname(os.path.abspath(sys.argv[0])) 1161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci src_dir = os.path.dirname(tools_dir) 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Collect the args into the right buckets 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) src_dirs = [] 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) grd_files = [] 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for arg in sys.argv[1:]: 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if arg.lower().endswith('.grd'): 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) grd_files.append(arg) 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else: 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) src_dirs.append(arg) 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # If no GRD files were given, default them: 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if len(grd_files) == 0: 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ash_base_dir = os.path.join(src_dir, 'ash') 1301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci athena_strings_dir = os.path.join(src_dir, 'athena', 'strings') 1311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci chrome_dir = os.path.join(src_dir, 'chrome') 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) chrome_app_dir = os.path.join(chrome_dir, 'app') 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) chrome_app_res_dir = os.path.join(chrome_app_dir, 'resources') 1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) device_base_dir = os.path.join(src_dir, 'device') 13503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) ui_dir = os.path.join(src_dir, 'ui') 13603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) ui_strings_dir = os.path.join(ui_dir, 'strings') 13703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) ui_chromeos_dir = os.path.join(ui_dir, 'chromeos') 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) grd_files = [ 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) os.path.join(ash_base_dir, 'ash_strings.grd'), 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) os.path.join(ash_base_dir, 'resources', 'ash_resources.grd'), 1411320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci os.path.join(athena_strings_dir, 'athena_strings.grd'), 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) os.path.join(chrome_app_dir, 'chromium_strings.grd'), 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) os.path.join(chrome_app_dir, 'generated_resources.grd'), 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) os.path.join(chrome_app_dir, 'google_chrome_strings.grd'), 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) os.path.join(chrome_app_res_dir, 'locale_settings.grd'), 1462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) os.path.join(chrome_app_res_dir, 'locale_settings_chromiumos.grd'), 1472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) os.path.join(chrome_app_res_dir, 'locale_settings_google_chromeos.grd'), 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) os.path.join(chrome_app_res_dir, 'locale_settings_linux.grd'), 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) os.path.join(chrome_app_res_dir, 'locale_settings_mac.grd'), 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) os.path.join(chrome_app_res_dir, 'locale_settings_win.grd'), 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) os.path.join(chrome_app_dir, 'theme', 'theme_resources.grd'), 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) os.path.join(chrome_dir, 'browser', 'browser_resources.grd'), 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) os.path.join(chrome_dir, 'common', 'common_resources.grd'), 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) os.path.join(chrome_dir, 'renderer', 'resources', 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'renderer_resources.grd'), 156868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) os.path.join(device_base_dir, 'bluetooth', 'bluetooth_strings.grd'), 1570529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch os.path.join(src_dir, 'extensions', 'extensions_strings.grd'), 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) os.path.join(src_dir, 'ui', 'resources', 'ui_resources.grd'), 1592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) os.path.join(src_dir, 'ui', 'webui', 'resources', 'webui_resources.grd'), 16003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) os.path.join(ui_strings_dir, 'app_locale_settings.grd'), 16103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) os.path.join(ui_strings_dir, 'ui_strings.grd'), 162116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch os.path.join(ui_chromeos_dir, 'ui_chromeos_strings.grd'), 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ] 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # If no source directories were given, default them: 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if len(src_dirs) == 0: 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) src_dirs = [ 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) os.path.join(src_dir, 'app'), 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) os.path.join(src_dir, 'ash'), 1701320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci os.path.join(src_dir, 'athena'), 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) os.path.join(src_dir, 'chrome'), 1722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) os.path.join(src_dir, 'components'), 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) os.path.join(src_dir, 'content'), 1742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) os.path.join(src_dir, 'device'), 1750529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch os.path.join(src_dir, 'extensions'), 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) os.path.join(src_dir, 'ui'), 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # nsNSSCertHelper.cpp has a bunch of ids 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) os.path.join(src_dir, 'third_party', 'mozilla_security_manager'), 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) os.path.join(chrome_dir, 'installer'), 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ] 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return CheckForUnusedGrdIDsInSources(grd_files, src_dirs) 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)if __name__ == '__main__': 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sys.exit(main()) 187