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 3# found in the LICENSE file. 4 5from io import BytesIO 6import posixpath 7from zipfile import ZipFile 8 9from compiled_file_system import SingleFile 10 11 12class DirectoryZipper(object): 13 '''Creates zip files of whole directories. 14 ''' 15 16 def __init__(self, compiled_fs_factory, file_system): 17 self._file_system = file_system 18 self._zip_cache = compiled_fs_factory.Create(file_system, 19 self._MakeZipFile, 20 DirectoryZipper) 21 22 # NOTE: It's ok to specify SingleFile here even though this method reads 23 # multiple files. All files are underneath |base_dir|. If any file changes its 24 # stat will change, so the stat of |base_dir| will also change. 25 @SingleFile 26 def _MakeZipFile(self, base_dir, files): 27 base_dir = base_dir.strip('/') 28 zip_bytes = BytesIO() 29 with ZipFile(zip_bytes, mode='w') as zip_file: 30 futures_with_name = [ 31 (file_name, 32 self._file_system.ReadSingle(posixpath.join(base_dir, file_name))) 33 for file_name in files] 34 for file_name, future in futures_with_name: 35 file_contents = future.Get() 36 if isinstance(file_contents, unicode): 37 # Data is sometimes already cached as unicode. 38 file_contents = file_contents.encode('utf8') 39 # We want e.g. basic.zip to expand to basic/manifest.json etc, not 40 # chrome/common/extensions/.../basic/manifest.json, so only use the 41 # end of the path component when writing into the zip file. 42 dir_name = posixpath.basename(base_dir) 43 zip_file.writestr(posixpath.join(dir_name, file_name), file_contents) 44 return zip_bytes.getvalue() 45 46 def Zip(self, path): 47 '''Creates a new zip file from the recursive contents of |path| as returned 48 by |_zip_cache|. 49 50 Paths within the zip file will be relative to and include the last 51 component of |path|, such that when zipping foo/bar containing baf.txt and 52 qux.txt will return a zip file which unzips to bar/baz.txt and bar/qux.txt. 53 ''' 54 return self._zip_cache.GetFromFileListing(path) 55