OLD | NEW |
---|---|
1 # Copyright 2013 The Chromium Authors. All rights reserved. | 1 # Copyright 2013 The Chromium Authors. All rights reserved. |
2 # Use of this source code is governed by a BSD-style license that can be | 2 # Use of this source code is governed by a BSD-style license that can be |
3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
4 | 4 |
5 import ast | 5 import ast |
6 import contextlib | 6 import contextlib |
7 import fnmatch | 7 import fnmatch |
8 import json | 8 import json |
9 import os | 9 import os |
10 import pipes | 10 import pipes |
11 import re | 11 import re |
12 import shlex | 12 import shlex |
13 import shutil | 13 import shutil |
14 import subprocess | 14 import subprocess |
15 import sys | 15 import sys |
16 import tempfile | 16 import tempfile |
17 import zipfile | 17 import zipfile |
18 | 18 |
19 # Some clients do not add //build/android/gyp to PYTHONPATH. | 19 # Some clients do not add //build/android/gyp to PYTHONPATH. |
20 import md5_check # pylint: disable=relative-import | 20 import md5_check # pylint: disable=relative-import |
21 | 21 |
22 sys.path.append(os.path.join(os.path.dirname(__file__), os.pardir, os.pardir)) | 22 sys.path.append(os.path.join(os.path.dirname(__file__), os.pardir, os.pardir)) |
23 from pylib import constants | 23 from pylib import constants |
24 | 24 |
25 COLORAMA_ROOT = os.path.join(constants.DIR_SOURCE_ROOT, | 25 COLORAMA_ROOT = os.path.join(constants.DIR_SOURCE_ROOT, |
26 'third_party', 'colorama', 'src') | 26 'third_party', 'colorama', 'src') |
27 # aapt should ignore OWNERS files in addition the default ignore pattern. | 27 # aapt should ignore OWNERS files in addition the default ignore pattern. |
28 AAPT_IGNORE_PATTERN = ('!OWNERS:!.svn:!.git:!.ds_store:!*.scc:.*:<dir>_*:' + | 28 AAPT_IGNORE_PATTERN = ('!OWNERS:!.svn:!.git:!.ds_store:!*.scc:.*:<dir>_*:' + |
29 '!CVS:!thumbs.db:!picasa.ini:!*~:!*.d.stamp') | 29 '!CVS:!thumbs.db:!picasa.ini:!*~:!*.d.stamp') |
30 HERMETIC_TIMESTAMP = (2001, 1, 1, 0, 0, 0) | 30 _HERMETIC_TIMESTAMP = (2001, 1, 1, 0, 0, 0) |
31 HERMETIC_FILE_ATTR = (0644 << 16L) | 31 _HERMETIC_FILE_ATTR = (0644 << 16L) |
32 | 32 |
33 | 33 |
34 @contextlib.contextmanager | 34 @contextlib.contextmanager |
35 def TempDir(): | 35 def TempDir(): |
36 dirname = tempfile.mkdtemp() | 36 dirname = tempfile.mkdtemp() |
37 try: | 37 try: |
38 yield dirname | 38 yield dirname |
39 finally: | 39 finally: |
40 shutil.rmtree(dirname) | 40 shutil.rmtree(dirname) |
41 | 41 |
(...skipping 175 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
217 CheckZipPath(name) | 217 CheckZipPath(name) |
218 if no_clobber: | 218 if no_clobber: |
219 output_path = os.path.join(path, name) | 219 output_path = os.path.join(path, name) |
220 if os.path.exists(output_path): | 220 if os.path.exists(output_path): |
221 raise Exception( | 221 raise Exception( |
222 'Path already exists from zip: %s %s %s' | 222 'Path already exists from zip: %s %s %s' |
223 % (zip_path, name, output_path)) | 223 % (zip_path, name, output_path)) |
224 z.extract(name, path) | 224 z.extract(name, path) |
225 | 225 |
226 | 226 |
227 def CreateHermeticZipInfo(zip_path): | 227 def AddToZipHermetic(zip_file, zip_path, src_path=None, data=None, |
228 """Creates a ZipInfo with a zero'ed out timestamp.""" | 228 compress=None): |
229 """Adds a file to the given ZipFile with a hard-coded modified time. | |
230 | |
231 Args: | |
232 zip_file: ZipFile instance to add the file to. | |
233 zip_path: Destination path within the zip file. | |
234 src_path: Path of the source file. Mutually exclusive with |data|. | |
235 data: File data as a string. | |
236 compress: Whether to enable compression. Default is take from ZipFile | |
237 constructor. | |
238 """ | |
239 assert (not src_path) != (not data), ( | |
jbudorick
2015/11/17 03:27:17
I was really confused by the original version of t
agrieve
2015/11/17 03:43:01
embarrassingly, didn't know about bool() :P
| |
240 '|src_path| and |data| are mutually exclusive.') | |
229 CheckZipPath(zip_path) | 241 CheckZipPath(zip_path) |
230 zipinfo = zipfile.ZipInfo(filename=zip_path, date_time=HERMETIC_TIMESTAMP) | 242 zipinfo = zipfile.ZipInfo(filename=zip_path, date_time=_HERMETIC_TIMESTAMP) |
231 zipinfo.external_attr = HERMETIC_FILE_ATTR | 243 zipinfo.external_attr = _HERMETIC_FILE_ATTR |
232 return zipinfo | 244 |
245 if src_path: | |
246 with file(src_path) as f: | |
247 data = f.read() | |
248 | |
249 # zipfile will deflate even when it makes the file bigger. To avoid | |
250 # growing files, disable compression at an arbitrary cut off point. | |
251 if len(data) < 16: | |
252 compress = False | |
253 | |
254 # None converts to ZIP_STORED, when passed explicitly. | |
255 if compress is None: | |
jbudorick
2015/11/17 03:27:17
why isn't this just
zip_file.writestr(zipinfo,
agrieve
2015/11/17 03:43:01
Updated this logic to be a bit more clever and ela
| |
256 zip_file.writestr(zipinfo, data) | |
257 else: | |
258 compress_type = zipfile.ZIP_DEFLATED if compress else zipfile.ZIP_STORED | |
259 zip_file.writestr(zipinfo, data, compress_type) | |
233 | 260 |
234 | 261 |
235 def DoZip(inputs, output, base_dir=None): | 262 def DoZip(inputs, output, base_dir=None): |
236 """Creates a zip file from a list of files. | 263 """Creates a zip file from a list of files. |
237 | 264 |
238 Args: | 265 Args: |
239 inputs: A list of paths to zip, or a list of (zip_path, fs_path) tuples. | 266 inputs: A list of paths to zip, or a list of (zip_path, fs_path) tuples. |
240 output: Destination .zip file. | 267 output: Destination .zip file. |
241 base_dir: Prefix to strip from inputs. | 268 base_dir: Prefix to strip from inputs. |
242 """ | 269 """ |
243 input_tuples = [] | 270 input_tuples = [] |
244 for tup in inputs: | 271 for tup in inputs: |
245 if isinstance(tup, basestring): | 272 if isinstance(tup, basestring): |
246 tup = (os.path.relpath(tup, base_dir), tup) | 273 tup = (os.path.relpath(tup, base_dir), tup) |
247 input_tuples.append(tup) | 274 input_tuples.append(tup) |
248 | 275 |
249 # Sort by zip path to ensure stable zip ordering. | 276 # Sort by zip path to ensure stable zip ordering. |
250 input_tuples.sort(key=lambda tup: tup[0]) | 277 input_tuples.sort(key=lambda tup: tup[0]) |
251 with zipfile.ZipFile(output, 'w') as outfile: | 278 with zipfile.ZipFile(output, 'w') as outfile: |
252 for zip_path, fs_path in input_tuples: | 279 for zip_path, fs_path in input_tuples: |
253 with file(fs_path) as f: | 280 AddToZipHermetic(outfile, zip_path, src_path=fs_path) |
254 contents = f.read() | |
255 outfile.writestr(CreateHermeticZipInfo(zip_path), contents) | |
256 | 281 |
257 | 282 |
258 def ZipDir(output, base_dir): | 283 def ZipDir(output, base_dir): |
259 """Creates a zip file from a directory.""" | 284 """Creates a zip file from a directory.""" |
260 inputs = [] | 285 inputs = [] |
261 for root, _, files in os.walk(base_dir): | 286 for root, _, files in os.walk(base_dir): |
262 for f in files: | 287 for f in files: |
263 inputs.append(os.path.join(root, f)) | 288 inputs.append(os.path.join(root, f)) |
264 DoZip(inputs, output, base_dir) | 289 DoZip(inputs, output, base_dir) |
265 | 290 |
(...skipping 10 matching lines...) Expand all Loading... | |
276 with zipfile.ZipFile(output, 'w') as out_zip: | 301 with zipfile.ZipFile(output, 'w') as out_zip: |
277 for in_file in inputs: | 302 for in_file in inputs: |
278 with zipfile.ZipFile(in_file, 'r') as in_zip: | 303 with zipfile.ZipFile(in_file, 'r') as in_zip: |
279 for name in in_zip.namelist(): | 304 for name in in_zip.namelist(): |
280 # Ignore directories. | 305 # Ignore directories. |
281 if name[-1] == '/': | 306 if name[-1] == '/': |
282 continue | 307 continue |
283 dst_name = path_transform(name, in_file) | 308 dst_name = path_transform(name, in_file) |
284 already_added = dst_name in added_names | 309 already_added = dst_name in added_names |
285 if not already_added and not MatchesGlob(dst_name, exclude_patterns): | 310 if not already_added and not MatchesGlob(dst_name, exclude_patterns): |
286 out_zip.writestr(CreateHermeticZipInfo(dst_name), in_zip.read(name)) | 311 AddToZipHermetic(out_zip, dst_name, data=in_zip.read(name)) |
287 added_names.add(dst_name) | 312 added_names.add(dst_name) |
288 | 313 |
289 | 314 |
290 def PrintWarning(message): | 315 def PrintWarning(message): |
291 print 'WARNING: ' + message | 316 print 'WARNING: ' + message |
292 | 317 |
293 | 318 |
294 def PrintBigWarning(message): | 319 def PrintBigWarning(message): |
295 print '***** ' * 8 | 320 print '***** ' * 8 |
296 PrintWarning(message) | 321 PrintWarning(message) |
(...skipping 154 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
451 | 476 |
452 md5_check.CallAndRecordIfStale( | 477 md5_check.CallAndRecordIfStale( |
453 on_stale_md5, | 478 on_stale_md5, |
454 record_path=record_path, | 479 record_path=record_path, |
455 input_paths=input_paths, | 480 input_paths=input_paths, |
456 input_strings=input_strings, | 481 input_strings=input_strings, |
457 output_paths=output_paths, | 482 output_paths=output_paths, |
458 force=force, | 483 force=force, |
459 pass_changes=True) | 484 pass_changes=True) |
460 | 485 |
OLD | NEW |