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 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
73 """Returns (src, dest) given an asset path in the form src[:dest].""" | 73 """Returns (src, dest) given an asset path in the form src[:dest].""" |
74 path_parts = path.split(':') | 74 path_parts = path.split(':') |
75 src_path = path_parts[0] | 75 src_path = path_parts[0] |
76 if len(path_parts) > 1: | 76 if len(path_parts) > 1: |
77 dest_path = path_parts[1] | 77 dest_path = path_parts[1] |
78 else: | 78 else: |
79 dest_path = os.path.basename(src_path) | 79 dest_path = os.path.basename(src_path) |
80 return src_path, dest_path | 80 return src_path, dest_path |
81 | 81 |
82 | 82 |
83 def _AddAssets(apk, paths, disable_compression=False): | 83 def _ExpandPaths(paths): |
| 84 """Converts src:dst into tuples and enumerates files within directories. |
| 85 |
| 86 Args: |
| 87 paths: Paths in the form "src_path:dest_path" |
| 88 |
| 89 Returns: |
| 90 A list of (src_path, dest_path) tuples sorted by dest_path (for stable |
| 91 ordering within output .apk). |
| 92 """ |
| 93 ret = [] |
| 94 for path in paths: |
| 95 src_path, dest_path = _SplitAssetPath(path) |
| 96 if os.path.isdir(src_path): |
| 97 for f in build_utils.FindInDirectory(src_path, '*'): |
| 98 ret.append((f, os.path.join(dest_path, f[len(src_path) + 1:]))) |
| 99 else: |
| 100 ret.append((src_path, dest_path)) |
| 101 ret.sort(key=lambda t:t[1]) |
| 102 return ret |
| 103 |
| 104 |
| 105 def _AddAssets(apk, path_tuples, disable_compression=False): |
84 """Adds the given paths to the apk. | 106 """Adds the given paths to the apk. |
85 | 107 |
86 Args: | 108 Args: |
87 apk: ZipFile to write to. | 109 apk: ZipFile to write to. |
88 paths: List of paths (with optional :zipPath suffix) to add. | 110 paths: List of paths (with optional :zipPath suffix) to add. |
89 disable_compression: Whether to disable compression. | 111 disable_compression: Whether to disable compression. |
90 """ | 112 """ |
91 # Group all uncompressed assets together in the hope that it will increase | 113 # Group all uncompressed assets together in the hope that it will increase |
92 # locality of mmap'ed files. | 114 # locality of mmap'ed files. |
93 for target_compress in (False, True): | 115 for target_compress in (False, True): |
94 for path in paths: | 116 for src_path, dest_path in path_tuples: |
95 src_path, dest_path = _SplitAssetPath(path) | |
96 | 117 |
97 compress = not disable_compression and ( | 118 compress = not disable_compression and ( |
98 os.path.splitext(src_path)[1] not in _NO_COMPRESS_EXTENSIONS) | 119 os.path.splitext(src_path)[1] not in _NO_COMPRESS_EXTENSIONS) |
99 if target_compress == compress: | 120 if target_compress == compress: |
100 apk_path = 'assets/' + dest_path | 121 apk_path = 'assets/' + dest_path |
101 try: | 122 try: |
102 apk.getinfo(apk_path) | 123 apk.getinfo(apk_path) |
103 # Should never happen since write_build_config.py handles merging. | 124 # Should never happen since write_build_config.py handles merging. |
104 raise Exception('Multiple targets specified the asset path: %s' % | 125 raise Exception('Multiple targets specified the asset path: %s' % |
105 apk_path) | 126 apk_path) |
106 except KeyError: | 127 except KeyError: |
107 build_utils.AddToZipHermetic(apk, apk_path, src_path=src_path, | 128 build_utils.AddToZipHermetic(apk, apk_path, src_path=src_path, |
108 compress=compress) | 129 compress=compress) |
109 | 130 |
110 | 131 |
111 def _CreateAssetsList(paths): | 132 def _CreateAssetsList(path_tuples): |
112 """Returns a newline-separated list of asset paths for the given paths.""" | 133 """Returns a newline-separated list of asset paths for the given paths.""" |
113 return '\n'.join(_SplitAssetPath(p)[1] for p in sorted(paths)) + '\n' | 134 dests = sorted(t[1] for t in path_tuples) |
| 135 return '\n'.join(dests) + '\n' |
114 | 136 |
115 | 137 |
116 def main(args): | 138 def main(args): |
117 args = build_utils.ExpandFileArgs(args) | 139 args = build_utils.ExpandFileArgs(args) |
118 options = _ParseArgs(args) | 140 options = _ParseArgs(args) |
119 | 141 |
120 native_libs = [] | 142 native_libs = [] |
121 if options.native_libs_dir: | 143 if options.native_libs_dir: |
122 native_libs = _ListSubPaths(options.native_libs_dir) | 144 native_libs = _ListSubPaths(options.native_libs_dir) |
123 | 145 |
124 input_paths = [options.resource_apk, __file__] + native_libs | 146 input_paths = [options.resource_apk, __file__] + native_libs |
125 if options.dex_file: | 147 if options.dex_file: |
126 input_paths.append(options.dex_file) | 148 input_paths.append(options.dex_file) |
127 | 149 |
128 input_strings = [options.create_placeholder_lib, options.android_abi] | 150 input_strings = [options.create_placeholder_lib, options.android_abi] |
129 | 151 |
130 for path in itertools.chain(options.assets, options.uncompressed_assets): | 152 _assets = _ExpandPaths(options.assets) |
131 src_path, dest_path = _SplitAssetPath(path) | 153 _uncompressed_assets = _ExpandPaths(options.uncompressed_assets) |
| 154 |
| 155 for src_path, dest_path in itertools.chain(_assets, _uncompressed_assets): |
132 input_paths.append(src_path) | 156 input_paths.append(src_path) |
133 input_strings.append(dest_path) | 157 input_strings.append(dest_path) |
134 | 158 |
135 def on_stale_md5(): | 159 def on_stale_md5(): |
136 tmp_apk = options.output_apk + '.tmp' | 160 tmp_apk = options.output_apk + '.tmp' |
137 try: | 161 try: |
138 # Use a temp file to avoid creating an output if anything goes wrong. | 162 # Use a temp file to avoid creating an output if anything goes wrong. |
139 shutil.copyfile(options.resource_apk, tmp_apk) | 163 shutil.copyfile(options.resource_apk, tmp_apk) |
140 | 164 |
141 # TODO(agrieve): It would be more efficient to combine this step | 165 # TODO(agrieve): It would be more efficient to combine this step |
142 # with finalize_apk(), which sometimes aligns and uncompresses the | 166 # with finalize_apk(), which sometimes aligns and uncompresses the |
143 # native libraries. | 167 # native libraries. |
144 with zipfile.ZipFile(tmp_apk, 'a', zipfile.ZIP_DEFLATED) as apk: | 168 with zipfile.ZipFile(tmp_apk, 'a', zipfile.ZIP_DEFLATED) as apk: |
145 if options.write_asset_list: | 169 if options.write_asset_list: |
146 data = _CreateAssetsList( | 170 data = _CreateAssetsList( |
147 itertools.chain(options.assets, options.uncompressed_assets)) | 171 itertools.chain(_assets, _uncompressed_assets)) |
148 build_utils.AddToZipHermetic(apk, 'assets/assets_list', data=data) | 172 build_utils.AddToZipHermetic(apk, 'assets/assets_list', data=data) |
149 | 173 |
150 _AddAssets(apk, options.assets, disable_compression=False) | 174 _AddAssets(apk, _assets, disable_compression=False) |
151 _AddAssets(apk, options.uncompressed_assets, disable_compression=True) | 175 _AddAssets(apk, _uncompressed_assets, disable_compression=True) |
152 | 176 |
153 for path in native_libs: | 177 for path in native_libs: |
154 basename = os.path.basename(path) | 178 basename = os.path.basename(path) |
155 apk_path = 'lib/%s/%s' % (options.android_abi, basename) | 179 apk_path = 'lib/%s/%s' % (options.android_abi, basename) |
156 build_utils.AddToZipHermetic(apk, apk_path, src_path=path) | 180 build_utils.AddToZipHermetic(apk, apk_path, src_path=path) |
157 if options.create_placeholder_lib: | 181 if options.create_placeholder_lib: |
158 # Make it non-empty so that its checksum is non-zero and is not | 182 # Make it non-empty so that its checksum is non-zero and is not |
159 # ignored by md5_check. | 183 # ignored by md5_check. |
160 apk_path = 'lib/%s/libplaceholder.so' % options.android_abi | 184 apk_path = 'lib/%s/libplaceholder.so' % options.android_abi |
161 build_utils.AddToZipHermetic(apk, apk_path, data=':)') | 185 build_utils.AddToZipHermetic(apk, apk_path, data=':)') |
162 if options.dex_file: | 186 if options.dex_file: |
163 build_utils.AddToZipHermetic(apk, 'classes.dex', | 187 build_utils.AddToZipHermetic(apk, 'classes.dex', |
164 src_path=options.dex_file) | 188 src_path=options.dex_file) |
165 | 189 |
166 shutil.move(tmp_apk, options.output_apk) | 190 shutil.move(tmp_apk, options.output_apk) |
167 finally: | 191 finally: |
168 if os.path.exists(tmp_apk): | 192 if os.path.exists(tmp_apk): |
169 os.unlink(tmp_apk) | 193 os.unlink(tmp_apk) |
170 | 194 |
171 build_utils.CallAndWriteDepfileIfStale( | 195 build_utils.CallAndWriteDepfileIfStale( |
172 on_stale_md5, | 196 on_stale_md5, |
173 options, | 197 options, |
174 input_paths=input_paths, | 198 input_paths=input_paths, |
175 input_strings=input_strings, | 199 input_strings=input_strings, |
176 output_paths=[options.output_apk]) | 200 output_paths=[options.output_apk]) |
177 | 201 |
178 | 202 |
179 if __name__ == '__main__': | 203 if __name__ == '__main__': |
180 main(sys.argv[1:]) | 204 main(sys.argv[1:]) |
OLD | NEW |