OLD | NEW |
1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
2 # | 2 # |
3 # Copyright (c) 2015 The Chromium Authors. All rights reserved. | 3 # Copyright (c) 2015 The Chromium Authors. All rights reserved. |
4 # Use of this source code is governed by a BSD-style license that can be | 4 # Use of this source code is governed by a BSD-style license that can be |
5 # found in the LICENSE file. | 5 # found in the LICENSE file. |
6 | 6 |
7 """Adds the code parts to a resource APK.""" | 7 """Adds the code parts to a resource APK.""" |
8 | 8 |
9 import argparse | 9 import argparse |
10 import itertools | 10 import itertools |
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
78 """Returns (src, dest) given an asset path in the form src[:dest].""" | 78 """Returns (src, dest) given an asset path in the form src[:dest].""" |
79 path_parts = path.split(':') | 79 path_parts = path.split(':') |
80 src_path = path_parts[0] | 80 src_path = path_parts[0] |
81 if len(path_parts) > 1: | 81 if len(path_parts) > 1: |
82 dest_path = path_parts[1] | 82 dest_path = path_parts[1] |
83 else: | 83 else: |
84 dest_path = os.path.basename(src_path) | 84 dest_path = os.path.basename(src_path) |
85 return src_path, dest_path | 85 return src_path, dest_path |
86 | 86 |
87 | 87 |
88 def _AddAssets(apk, paths, disable_compression=False): | 88 def _ExpandPaths(paths): |
| 89 """Converts src:dst into tuples and enumerates files within directories. |
| 90 |
| 91 Args: |
| 92 paths: Paths in the form "src_path:dest_path" |
| 93 |
| 94 Returns: |
| 95 A list of (src_path, dest_path) tuples sorted by dest_path (for stable |
| 96 ordering within output .apk). |
| 97 """ |
| 98 ret = [] |
| 99 for path in paths: |
| 100 src_path, dest_path = _SplitAssetPath(path) |
| 101 if os.path.isdir(src_path): |
| 102 for f in build_utils.FindInDirectory(src_path, '*'): |
| 103 ret.append((f, os.path.join(dest_path, f[len(src_path) + 1:]))) |
| 104 else: |
| 105 ret.append((src_path, dest_path)) |
| 106 ret.sort(key=lambda t:t[1]) |
| 107 return ret |
| 108 |
| 109 |
| 110 def _AddAssets(apk, path_tuples, disable_compression=False): |
89 """Adds the given paths to the apk. | 111 """Adds the given paths to the apk. |
90 | 112 |
91 Args: | 113 Args: |
92 apk: ZipFile to write to. | 114 apk: ZipFile to write to. |
93 paths: List of paths (with optional :zipPath suffix) to add. | 115 paths: List of paths (with optional :zipPath suffix) to add. |
94 disable_compression: Whether to disable compression. | 116 disable_compression: Whether to disable compression. |
95 """ | 117 """ |
96 # Group all uncompressed assets together in the hope that it will increase | 118 # Group all uncompressed assets together in the hope that it will increase |
97 # locality of mmap'ed files. | 119 # locality of mmap'ed files. |
98 for target_compress in (False, True): | 120 for target_compress in (False, True): |
99 for path in paths: | 121 for src_path, dest_path in path_tuples: |
100 src_path, dest_path = _SplitAssetPath(path) | |
101 | 122 |
102 compress = not disable_compression and ( | 123 compress = not disable_compression and ( |
103 os.path.splitext(src_path)[1] not in _NO_COMPRESS_EXTENSIONS) | 124 os.path.splitext(src_path)[1] not in _NO_COMPRESS_EXTENSIONS) |
104 if target_compress == compress: | 125 if target_compress == compress: |
105 apk_path = 'assets/' + dest_path | 126 apk_path = 'assets/' + dest_path |
106 try: | 127 try: |
107 apk.getinfo(apk_path) | 128 apk.getinfo(apk_path) |
108 # Should never happen since write_build_config.py handles merging. | 129 # Should never happen since write_build_config.py handles merging. |
109 raise Exception('Multiple targets specified the asset path: %s' % | 130 raise Exception('Multiple targets specified the asset path: %s' % |
110 apk_path) | 131 apk_path) |
111 except KeyError: | 132 except KeyError: |
112 build_utils.AddToZipHermetic(apk, apk_path, src_path=src_path, | 133 build_utils.AddToZipHermetic(apk, apk_path, src_path=src_path, |
113 compress=compress) | 134 compress=compress) |
114 | 135 |
115 | 136 |
116 def _CreateAssetsList(paths): | 137 def _CreateAssetsList(path_tuples): |
117 """Returns a newline-separated list of asset paths for the given paths.""" | 138 """Returns a newline-separated list of asset paths for the given paths.""" |
118 return '\n'.join(_SplitAssetPath(p)[1] for p in sorted(paths)) + '\n' | 139 dests = sorted(t[1] for t in path_tuples) |
| 140 return '\n'.join(dests) + '\n' |
119 | 141 |
120 | 142 |
121 def main(args): | 143 def main(args): |
122 args = build_utils.ExpandFileArgs(args) | 144 args = build_utils.ExpandFileArgs(args) |
123 options = _ParseArgs(args) | 145 options = _ParseArgs(args) |
124 | 146 |
125 native_libs = sorted(options.native_libs) | 147 native_libs = sorted(options.native_libs) |
126 | 148 |
127 input_paths = [options.resource_apk, __file__] + native_libs | 149 input_paths = [options.resource_apk, __file__] + native_libs |
128 if options.dex_file: | 150 if options.dex_file: |
129 input_paths.append(options.dex_file) | 151 input_paths.append(options.dex_file) |
130 | 152 |
131 if options.emma_device_jar: | 153 if options.emma_device_jar: |
132 input_paths.append(options.emma_device_jar) | 154 input_paths.append(options.emma_device_jar) |
133 | 155 |
134 input_strings = [options.android_abi, options.native_lib_placeholders] | 156 input_strings = [options.android_abi, options.native_lib_placeholders] |
135 | 157 |
136 for path in itertools.chain(options.assets, options.uncompressed_assets): | 158 _assets = _ExpandPaths(options.assets) |
137 src_path, dest_path = _SplitAssetPath(path) | 159 _uncompressed_assets = _ExpandPaths(options.uncompressed_assets) |
| 160 |
| 161 for src_path, dest_path in itertools.chain(_assets, _uncompressed_assets): |
138 input_paths.append(src_path) | 162 input_paths.append(src_path) |
139 input_strings.append(dest_path) | 163 input_strings.append(dest_path) |
140 | 164 |
141 def on_stale_md5(): | 165 def on_stale_md5(): |
142 tmp_apk = options.output_apk + '.tmp' | 166 tmp_apk = options.output_apk + '.tmp' |
143 try: | 167 try: |
144 # TODO(agrieve): It would be more efficient to combine this step | 168 # TODO(agrieve): It would be more efficient to combine this step |
145 # with finalize_apk(), which sometimes aligns and uncompresses the | 169 # with finalize_apk(), which sometimes aligns and uncompresses the |
146 # native libraries. | 170 # native libraries. |
147 with zipfile.ZipFile(options.resource_apk) as resource_apk, \ | 171 with zipfile.ZipFile(options.resource_apk) as resource_apk, \ |
148 zipfile.ZipFile(tmp_apk, 'w', zipfile.ZIP_DEFLATED) as out_apk: | 172 zipfile.ZipFile(tmp_apk, 'w', zipfile.ZIP_DEFLATED) as out_apk: |
149 def copy_resource(zipinfo): | 173 def copy_resource(zipinfo): |
150 compress = zipinfo.compress_type != zipfile.ZIP_STORED | 174 compress = zipinfo.compress_type != zipfile.ZIP_STORED |
151 build_utils.AddToZipHermetic(out_apk, zipinfo.filename, | 175 build_utils.AddToZipHermetic(out_apk, zipinfo.filename, |
152 data=resource_apk.read(zipinfo.filename), | 176 data=resource_apk.read(zipinfo.filename), |
153 compress=compress) | 177 compress=compress) |
154 | 178 |
155 # Make assets come before resources in order to maintain the same file | 179 # Make assets come before resources in order to maintain the same file |
156 # ordering as GYP / aapt. http://crbug.com/561862 | 180 # ordering as GYP / aapt. http://crbug.com/561862 |
157 resource_infos = resource_apk.infolist() | 181 resource_infos = resource_apk.infolist() |
158 | 182 |
159 # 1. AndroidManifest.xml | 183 # 1. AndroidManifest.xml |
160 assert resource_infos[0].filename == 'AndroidManifest.xml' | 184 assert resource_infos[0].filename == 'AndroidManifest.xml' |
161 copy_resource(resource_infos[0]) | 185 copy_resource(resource_infos[0]) |
162 | 186 |
163 # 2. Assets | 187 # 2. Assets |
164 if options.write_asset_list: | 188 if options.write_asset_list: |
165 data = _CreateAssetsList( | 189 data = _CreateAssetsList( |
166 itertools.chain(options.assets, options.uncompressed_assets)) | 190 itertools.chain(_assets, _uncompressed_assets)) |
167 build_utils.AddToZipHermetic(out_apk, 'assets/assets_list', data=data) | 191 build_utils.AddToZipHermetic(out_apk, 'assets/assets_list', data=data) |
168 | 192 |
169 _AddAssets(out_apk, options.assets, disable_compression=False) | 193 _AddAssets(out_apk, _assets, disable_compression=False) |
170 _AddAssets(out_apk, options.uncompressed_assets, | 194 _AddAssets(out_apk, _uncompressed_assets, disable_compression=True) |
171 disable_compression=True) | |
172 | 195 |
173 # 3. Resources | 196 # 3. Resources |
174 for info in resource_infos[1:]: | 197 for info in resource_infos[1:]: |
175 copy_resource(info) | 198 copy_resource(info) |
176 | 199 |
177 # 4. Dex files | 200 # 4. Dex files |
178 if options.dex_file and options.dex_file.endswith('.zip'): | 201 if options.dex_file and options.dex_file.endswith('.zip'): |
179 with zipfile.ZipFile(options.dex_file, 'r') as dex_zip: | 202 with zipfile.ZipFile(options.dex_file, 'r') as dex_zip: |
180 for dex in (d for d in dex_zip.namelist() if d.endswith('.dex')): | 203 for dex in (d for d in dex_zip.namelist() if d.endswith('.dex')): |
181 build_utils.AddToZipHermetic(out_apk, dex, data=dex_zip.read(dex)) | 204 build_utils.AddToZipHermetic(out_apk, dex, data=dex_zip.read(dex)) |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
222 build_utils.CallAndWriteDepfileIfStale( | 245 build_utils.CallAndWriteDepfileIfStale( |
223 on_stale_md5, | 246 on_stale_md5, |
224 options, | 247 options, |
225 input_paths=input_paths, | 248 input_paths=input_paths, |
226 input_strings=input_strings, | 249 input_strings=input_strings, |
227 output_paths=[options.output_apk]) | 250 output_paths=[options.output_apk]) |
228 | 251 |
229 | 252 |
230 if __name__ == '__main__': | 253 if __name__ == '__main__': |
231 main(sys.argv[1:]) | 254 main(sys.argv[1:]) |
OLD | NEW |