Home | History | Annotate | Download | only in server2
      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 
      5 from io import BytesIO
      6 import posixpath
      7 from zipfile import ZipFile
      8 
      9 from compiled_file_system import SingleFile
     10 
     11 
     12 class 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