Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(390)

Side by Side Diff: tools/android/find_unused_resources.py

Issue 23591017: Update find_unused_resources.py to ignore third party resources. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: hide attrs and ids Created 7 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 #!/usr/bin/python 1 #!/usr/bin/python
2 # Copyright (c) 2013 The Chromium Authors. All rights reserved. 2 # Copyright (c) 2013 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be 3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file. 4 # found in the LICENSE file.
5 5
6 """Lists unused Java strings and other resources.""" 6 """Lists unused Java strings and other resources."""
7 7
8 import optparse 8 import optparse
9 import re 9 import re
10 import subprocess 10 import subprocess
11 import sys 11 import sys
12 12
13 13
14 def GetApkResources(apk_path): 14 def GetLibraryResources(r_txt_paths):
15 """Returns the types and names of resources packaged in an APK. 15 """Returns the resources packaged in a list of libraries.
16 16
17 Args: 17 Args:
18 apk_path: path to the APK. 18 r_txt_paths: paths to each library's generated R.txt file which lists the
19 resources it contains.
19 20
20 Returns: 21 Returns:
21 The resources in the APK as a list of tuples (type, name). Example: 22 The resources in the libraries as a list of tuples (type, name). Example:
22 [('drawable', 'arrow'), ('layout', 'month_picker'), ...] 23 [('drawable', 'arrow'), ('layout', 'month_picker'), ...]
23 """ 24 """
24 p = subprocess.Popen( 25 resources = []
25 ['aapt', 'dump', 'resources', apk_path], 26 for r_txt_path in r_txt_paths:
26 stdout=subprocess.PIPE) 27 with open(r_txt_path, 'r') as f:
27 dump_out, _ = p.communicate() 28 for line in f:
28 assert p.returncode == 0, 'aapt dump failed' 29 line = line.strip()
29 matches = re.finditer( 30 if not line:
30 r'^\s+spec resource 0x[0-9a-fA-F]+ [\w.]+:(?P<type>\w+)/(?P<name>\w+)', 31 continue
31 dump_out, re.MULTILINE) 32 data_type, res_type, name, _ = line.split(None, 3)
cjhopman 2013/09/06 00:38:08 what's the format of these lines in R.txt?
newt (away) 2013/09/06 00:49:50 int string sign_in 0x7f0800ac int styleable Theme_
32 return [m.group('type', 'name') for m in matches] 33 assert data_type in ('int', 'int[]')
34 # Hide attrs, which are redundant with styleables and always appear
35 # unused, and hide ids, which are innocuous even if unused.
36 if res_type in ('attr', 'id'):
37 continue
38 resources.append((res_type, name))
39 return resources
33 40
34 41
35 def GetUsedResources(source_paths, resource_types): 42 def GetUsedResources(source_paths, resource_types):
36 """Returns the types and names of resources used in Java or resource files. 43 """Returns the types and names of resources used in Java or resource files.
37 44
38 Args: 45 Args:
39 source_paths: a list of files or folders collectively containing all the 46 source_paths: a list of files or folders collectively containing all the
40 Java files, resource files, and the AndroidManifest.xml. 47 Java files, resource files, and the AndroidManifest.xml.
41 resource_types: a list of resource types to look for. Example: 48 resource_types: a list of resource types to look for. Example:
42 ['string', 'drawable'] 49 ['string', 'drawable']
(...skipping 29 matching lines...) Expand all
72 def FormatResources(resources): 79 def FormatResources(resources):
73 """Formats a list of resources for printing. 80 """Formats a list of resources for printing.
74 81
75 Args: 82 Args:
76 resources: a list of resources, given as (type, name) tuples. 83 resources: a list of resources, given as (type, name) tuples.
77 """ 84 """
78 return '\n'.join(['%-12s %s' % (t, n) for t, n in sorted(resources)]) 85 return '\n'.join(['%-12s %s' % (t, n) for t, n in sorted(resources)])
79 86
80 87
81 def ParseArgs(args): 88 def ParseArgs(args):
82 usage = 'usage: %prog [-v] APK_PATH SOURCE_PATH...' 89 parser = optparse.OptionParser()
83 parser = optparse.OptionParser(usage=usage)
84 parser.add_option('-v', help='Show verbose output', action='store_true') 90 parser.add_option('-v', help='Show verbose output', action='store_true')
91 parser.add_option('-s', '--source-path', help='Specify a source folder path '
92 '(e.g. ui/android/java)', action='append', default=[])
93 parser.add_option('-r', '--r-txt-path', help='Specify a "first-party" R.txt '
94 'file (e.g. out/Debug/content_shell_apk/R.txt)',
95 action='append', default=[])
96 parser.add_option('-t', '--third-party-r-txt-path', help='Specify an R.txt '
97 'file for a third party library', action='append',
98 default=[])
85 options, args = parser.parse_args(args=args) 99 options, args = parser.parse_args(args=args)
86 if len(args) < 2: 100 if args:
87 parser.error('must provide APK_PATH and SOURCE_PATH arguments') 101 parser.error('positional arguments not allowed')
88 return options.v, args[0], args[1:] 102 if not options.source_path:
103 parser.error('at least one source folder path must be specified with -s')
104 if not options.r_txt_path:
105 parser.error('at least one R.txt path must be specified with -r')
106 return (options.v, options.source_path, options.r_txt_path,
107 options.third_party_r_txt_path)
89 108
90 109
91 def main(args=None): 110 def main(args=None):
92 verbose, apk_path, source_paths = ParseArgs(args) 111 verbose, source_paths, r_txt_paths, third_party_r_txt_paths = ParseArgs(args)
93 apk_resources = GetApkResources(apk_path) 112 defined_resources = (set(GetLibraryResources(r_txt_paths)) -
94 resource_types = list(set([r[0] for r in apk_resources])) 113 set(GetLibraryResources(third_party_r_txt_paths)))
95 used_resources = GetUsedResources(source_paths, resource_types) 114 resource_types = list(set([r[0] for r in defined_resources]))
96 unused_resources = set(apk_resources) - set(used_resources) 115 used_resources = set(GetUsedResources(source_paths, resource_types))
97 undefined_resources = set(used_resources) - set(apk_resources) 116 unused_resources = defined_resources - used_resources
117 undefined_resources = used_resources - defined_resources
98 118
99 # aapt dump fails silently. Notify the user if things look wrong. 119 # aapt dump fails silently. Notify the user if things look wrong.
100 if not apk_resources: 120 if not defined_resources:
101 print >> sys.stderr, ( 121 print >> sys.stderr, (
102 'Warning: No resources found in the APK. Did you provide the correct ' 122 'Warning: No resources found. Did you provide the correct R.txt paths?')
103 'APK path?')
104 if not used_resources: 123 if not used_resources:
105 print >> sys.stderr, ( 124 print >> sys.stderr, (
106 'Warning: No resources references from Java or resource files. Did you ' 125 'Warning: No resources referenced from Java or resource files. Did you '
107 'provide the correct source paths?') 126 'provide the correct source paths?')
108 if undefined_resources: 127 if undefined_resources:
109 print >> sys.stderr, ( 128 print >> sys.stderr, (
110 'Warning: found %d "undefined" resources that are referenced by Java ' 129 'Warning: found %d "undefined" resources that are referenced by Java '
111 'files or by other resources, but are not in the APK. Run with -v to ' 130 'files or by other resources, but are not defined anywhere. Run with '
112 'see them.' % len(undefined_resources)) 131 '-v to see them.' % len(undefined_resources))
113 132
114 if verbose: 133 if verbose:
115 print '%d undefined resources:' % len(undefined_resources) 134 print '%d undefined resources:' % len(undefined_resources)
116 print FormatResources(undefined_resources), '\n' 135 print FormatResources(undefined_resources), '\n'
117 print '%d resources packaged into the APK:' % len(apk_resources) 136 print '%d resources defined:' % len(defined_resources)
118 print FormatResources(apk_resources), '\n' 137 print FormatResources(defined_resources), '\n'
119 print '%d used resources:' % len(used_resources) 138 print '%d used resources:' % len(used_resources)
120 print FormatResources(used_resources), '\n' 139 print FormatResources(used_resources), '\n'
121 print '%d unused resources:' % len(unused_resources) 140 print '%d unused resources:' % len(unused_resources)
122 print FormatResources(unused_resources) 141 print FormatResources(unused_resources)
123 142
124 143
125 if __name__ == '__main__': 144 if __name__ == '__main__':
126 main() 145 main()
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698