Upload upstream chromium 67.0.3396
[platform/framework/web/chromium-efl.git] / tools / check_grd_for_unused_strings.py
1 #!/usr/bin/env python
2 # Copyright (c) 2012 The Chromium Authors. All rights reserved.
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
13 import os
14 import re
15 import sys
16 import xml.sax
17
18 # Extra messages along the way
19 # 1 - Print ids that are found in sources but not in the found id set
20 # 2 - Files that aren't processes (don't match the source name regex)
21 DEBUG = 0
22
23
24 class GrdIDExtractor(xml.sax.handler.ContentHandler):
25   """Extracts the IDs from messages in GRIT files"""
26   def __init__(self):
27     self.id_set_ = set()
28
29   def startElement(self, name, attrs):
30     if name == 'message':
31       self.id_set_.add(attrs['name'])
32
33   def allIDs(self):
34     """Return all the IDs found"""
35     return self.id_set_.copy()
36
37
38 def CheckForUnusedGrdIDsInSources(grd_files, src_dirs):
39   """Will collect the message ids out of the given GRD files and then scan
40   the source directories to try and figure out what ids are not currently
41   being used by any source.
42
43   grd_files:
44     A list of GRD files to collect the ids from.
45   src_dirs:
46     A list of directories to walk looking for source files.
47   """
48   # Collect all the ids into a large map
49   all_ids = set()
50   file_id_map = {}
51   for y in grd_files:
52     handler = GrdIDExtractor()
53     xml.sax.parse(y, handler)
54     files_ids = handler.allIDs()
55     file_id_map[y] = files_ids
56     all_ids |= files_ids
57
58
59   # The regex that will be used to check sources
60   id_regex = re.compile('IDS_[A-Z0-9_]+')
61
62   # Make sure the regex matches every id found.
63   got_err = False
64   for x in all_ids:
65     match = id_regex.search(x)
66     if match is None:
67       print 'ERROR: "%s" did not match our regex' % (x)
68       got_err = True
69     if not match.group(0) is x:
70       print 'ERROR: "%s" did not fully match our regex' % (x)
71       got_err = True
72   if got_err:
73     return 1
74
75   # The regex for deciding what is a source file
76   src_regex = re.compile('\.(([chm])|(mm)|(cc)|(cp)|(cpp)|(xib)|(py))$')
77
78   ids_left = all_ids.copy()
79
80   # Scanning time.
81   for src_dir in src_dirs:
82     for root, dirs, files in os.walk(src_dir):
83       # Remove svn directories from recursion
84       if '.svn' in dirs:
85         dirs.remove('.svn')
86       for file in files:
87         if src_regex.search(file.lower()):
88           full_path = os.path.join(root, file)
89           src_file_contents = open(full_path).read()
90           for match in sorted(set(id_regex.findall(src_file_contents))):
91             if match in ids_left:
92               ids_left.remove(match)
93             if DEBUG:
94               if not match in all_ids:
95                 print '%s had "%s", which was not in the found IDs' % \
96                   (full_path, match)
97         elif DEBUG > 1:
98           full_path = os.path.join(root, file)
99           print 'Skipping %s.' % (full_path)
100
101   # Anything left?
102   if len(ids_left) > 0:
103     print 'The following ids are in GRD files, but *appear* to be unused:'
104     for file_path, file_ids in file_id_map.iteritems():
105       missing = ids_left.intersection(file_ids)
106       if len(missing) > 0:
107         print '  %s:' % (file_path)
108         print '\n'.join('    %s' % (x) for x in sorted(missing))
109
110   return 0
111
112
113 def main():
114   # script lives in src/tools
115   tools_dir = os.path.dirname(os.path.abspath(sys.argv[0]))
116   src_dir = os.path.dirname(tools_dir)
117
118   # Collect the args into the right buckets
119   src_dirs = []
120   grd_files = []
121   for arg in sys.argv[1:]:
122     if arg.lower().endswith('.grd') or arg.lower().endswith('.grdp'):
123       grd_files.append(arg)
124     else:
125       src_dirs.append(arg)
126
127   # If no GRD files were given, default them:
128   if len(grd_files) == 0:
129     ash_base_dir = os.path.join(src_dir, 'ash')
130     ash_components_dir = os.path.join(ash_base_dir, 'components')
131     chrome_dir = os.path.join(src_dir, 'chrome')
132     chrome_app_dir = os.path.join(chrome_dir, 'app')
133     chrome_app_res_dir = os.path.join(chrome_app_dir, 'resources')
134     device_base_dir = os.path.join(src_dir, 'device')
135     ui_dir = os.path.join(src_dir, 'ui')
136     ui_strings_dir = os.path.join(ui_dir, 'strings')
137     ui_chromeos_dir = os.path.join(ui_dir, 'chromeos')
138     grd_files = [
139       os.path.join(ash_base_dir, 'ash_strings.grd'),
140       os.path.join(ash_base_dir, 'resources', 'ash_resources.grd'),
141       os.path.join(ash_components_dir, 'ash_components_strings.grd'),
142       os.path.join(ash_components_dir, 'resources',
143                    'ash_components_resources.grd'),
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'),
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'),
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'),
156       os.path.join(chrome_dir, 'renderer', 'resources',
157                    'renderer_resources.grd'),
158       os.path.join(device_base_dir, 'bluetooth', 'bluetooth_strings.grd'),
159       os.path.join(src_dir, 'extensions', 'strings', 'extensions_strings.grd'),
160       os.path.join(src_dir, 'ui', 'resources', 'ui_resources.grd'),
161       os.path.join(src_dir, 'ui', 'webui', 'resources', 'webui_resources.grd'),
162       os.path.join(ui_strings_dir, 'app_locale_settings.grd'),
163       os.path.join(ui_strings_dir, 'ui_strings.grd'),
164       os.path.join(ui_chromeos_dir, 'ui_chromeos_strings.grd'),
165     ]
166
167   # If no source directories were given, default them:
168   if len(src_dirs) == 0:
169     src_dirs = [
170       os.path.join(src_dir, 'app'),
171       os.path.join(src_dir, 'ash'),
172       os.path.join(src_dir, 'chrome'),
173       os.path.join(src_dir, 'components'),
174       os.path.join(src_dir, 'content'),
175       os.path.join(src_dir, 'device'),
176       os.path.join(src_dir, 'extensions'),
177       os.path.join(src_dir, 'ui'),
178       # nsNSSCertHelper.cpp has a bunch of ids
179       os.path.join(src_dir, 'third_party', 'mozilla_security_manager'),
180       os.path.join(chrome_dir, 'installer'),
181     ]
182
183   return CheckForUnusedGrdIDsInSources(grd_files, src_dirs)
184
185
186 if __name__ == '__main__':
187   sys.exit(main())