Upload upstream chromium 108.0.5359.1
[platform/framework/web/chromium-efl.git] / tools / check_grd_for_unused_strings.py
1 #!/usr/bin/env python
2 # Copyright 2012 The Chromium Authors
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 from __future__ import print_function
14
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:
69       print('ERROR: "%s" did not match our regex' % x)
70       got_err = True
71     if not match.group(0) is x:
72       print('ERROR: "%s" did not fully match our regex' % x)
73       got_err = True
74   if got_err:
75     return 1
76
77   # The regex for deciding what is a source file
78   src_regex = re.compile('\.(([chm])|(mm)|(cc)|(cp)|(cpp)|(xib)|(py))$')
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:
97                 print('%s had "%s", which was not in the found IDs' % \
98                   (full_path, match))
99         elif DEBUG > 1:
100           full_path = os.path.join(root, file)
101           print('Skipping %s.' % full_path)
102
103   # Anything left?
104   if len(ids_left) > 0:
105     print('The following ids are in GRD files, but *appear* to be unused:')
106     for file_path, file_ids in file_id_map.iteritems():
107       missing = ids_left.intersection(file_ids)
108       if len(missing) > 0:
109         print('  %s:' % file_path)
110         print('\n'.join('    %s' % (x) for x in sorted(missing)))
111
112   return 0
113
114
115 def main():
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)
119
120   # Collect the args into the right buckets
121   src_dirs = []
122   grd_files = []
123   for arg in sys.argv[1:]:
124     if arg.lower().endswith('.grd') or arg.lower().endswith('.grdp'):
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:
131     ash_base_dir = os.path.join(src_dir, 'ash')
132     ash_shortcut_viewer_dir = os.path.join(ash_base_dir, 'shortcut_viewer')
133     chrome_dir = os.path.join(src_dir, 'chrome')
134     chrome_app_dir = os.path.join(chrome_dir, 'app')
135     chrome_app_res_dir = os.path.join(chrome_app_dir, 'resources')
136     device_base_dir = os.path.join(src_dir, 'device')
137     services_dir = os.path.join(src_dir, 'services')
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')
141     grd_files = [
142         os.path.join(ash_base_dir, 'ash_strings.grd'),
143         os.path.join(ash_shortcut_viewer_dir, 'shortcut_viewer_strings.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(device_base_dir, 'fido', 'fido_strings.grd'),
160         os.path.join(services_dir, 'services_strings.grd'),
161         os.path.join(src_dir, 'chromeos', 'chromeos_strings.grd'),
162         os.path.join(src_dir, 'extensions', 'strings',
163                      'extensions_strings.grd'),
164         os.path.join(src_dir, 'ui', 'resources', 'ui_resources.grd'),
165         os.path.join(src_dir, 'ui', 'webui', 'resources',
166                      'webui_resources.grd'),
167         os.path.join(ui_strings_dir, 'app_locale_settings.grd'),
168         os.path.join(ui_strings_dir, 'ax_strings.grd'),
169         os.path.join(ui_strings_dir, 'ui_strings.grd'),
170         os.path.join(ui_chromeos_dir, 'ui_chromeos_strings.grd'),
171     ]
172
173   # If no source directories were given, default them:
174   if len(src_dirs) == 0:
175     src_dirs = [
176       os.path.join(src_dir, 'app'),
177       os.path.join(src_dir, 'ash'),
178       os.path.join(src_dir, 'chrome'),
179       os.path.join(src_dir, 'components'),
180       os.path.join(src_dir, 'content'),
181       os.path.join(src_dir, 'device'),
182       os.path.join(src_dir, 'extensions'),
183       os.path.join(src_dir, 'ui'),
184       # nsNSSCertHelper.cpp has a bunch of ids
185       os.path.join(src_dir, 'third_party', 'mozilla_security_manager'),
186       os.path.join(chrome_dir, 'installer'),
187     ]
188
189   return CheckForUnusedGrdIDsInSources(grd_files, src_dirs)
190
191
192 if __name__ == '__main__':
193   sys.exit(main())