1#!/usr/bin/env python 2# 3# Copyright 2016 Google Inc. 4# 5# Use of this source code is governed by a BSD-style license that can be 6# found in the LICENSE file. 7 8 9"""Utilities for zipping and unzipping files.""" 10 11 12import fnmatch 13import ntpath 14import os 15import posixpath 16import zipfile 17 18 19def filtered(names, blacklist): 20 """Filter the list of file or directory names.""" 21 rv = names[:] 22 for pattern in blacklist: 23 rv = [n for n in rv if not fnmatch.fnmatch(n, pattern)] 24 return rv 25 26 27def zip(target_dir, zip_file, blacklist=None): # pylint: disable=W0622 28 """Zip the given directory, write to the given zip file.""" 29 if not os.path.isdir(target_dir): 30 raise IOError('%s does not exist!' % target_dir) 31 blacklist = blacklist or [] 32 with zipfile.ZipFile(zip_file, 'w', zipfile.ZIP_DEFLATED, True) as z: 33 for r, d, f in os.walk(target_dir, topdown=True): 34 d[:] = filtered(d, blacklist) 35 for filename in filtered(f, blacklist): 36 filepath = os.path.join(r, filename) 37 zi = zipfile.ZipInfo(filepath) 38 zi.filename = os.path.relpath(filepath, target_dir) 39 if os.name == 'nt': 40 # Dumb path separator replacement for Windows. 41 zi.filename = zi.filename.replace(ntpath.sep, posixpath.sep) 42 try: 43 perms = os.stat(filepath).st_mode 44 except OSError: 45 if os.path.islink(filepath): 46 print 'Skipping symlink %s' % filepath 47 continue 48 else: 49 raise 50 zi.external_attr = perms << 16L 51 zi.compress_type = zipfile.ZIP_DEFLATED 52 with open(filepath, 'rb') as f: 53 content = f.read() 54 z.writestr(zi, content) 55 for dirname in d: 56 dirpath = os.path.join(r, dirname) 57 z.write(dirpath, os.path.relpath(dirpath, target_dir)) 58 59 60def unzip(zip_file, target_dir): 61 """Unzip the given zip file into the target dir.""" 62 if not os.path.isdir(target_dir): 63 os.makedirs(target_dir) 64 with zipfile.ZipFile(zip_file, 'r', zipfile.ZIP_DEFLATED, True) as z: 65 for zi in z.infolist(): 66 dst_subpath = zi.filename 67 if os.name == 'nt': 68 # Dumb path separator replacement for Windows. 69 dst_subpath = dst_subpath.replace(posixpath.sep, ntpath.sep) 70 dst_path = os.path.join(target_dir, dst_subpath) 71 if dst_path.endswith(os.path.sep): 72 os.mkdir(dst_path) 73 else: 74 with open(dst_path, 'wb') as f: 75 f.write(z.read(zi)) 76 perms = zi.external_attr >> 16L 77 os.chmod(dst_path, perms) 78