2016-06-15 19:07:42 +00:00
|
|
|
#!/usr/bin/env python
|
|
|
|
#
|
|
|
|
# Copyright 2016 Google Inc.
|
|
|
|
#
|
|
|
|
# Use of this source code is governed by a BSD-style license that can be
|
|
|
|
# found in the LICENSE file.
|
|
|
|
|
|
|
|
|
|
|
|
"""Utilities for zipping and unzipping files."""
|
|
|
|
|
|
|
|
|
2021-03-25 13:04:43 +00:00
|
|
|
from __future__ import print_function
|
2016-06-15 19:07:42 +00:00
|
|
|
import fnmatch
|
2017-09-28 16:31:32 +00:00
|
|
|
import ntpath
|
2016-06-15 19:07:42 +00:00
|
|
|
import os
|
2017-09-28 16:31:32 +00:00
|
|
|
import posixpath
|
2016-06-15 19:07:42 +00:00
|
|
|
import zipfile
|
|
|
|
|
|
|
|
|
2020-07-24 17:37:32 +00:00
|
|
|
def filtered(names, to_skip):
|
2016-06-15 19:07:42 +00:00
|
|
|
"""Filter the list of file or directory names."""
|
|
|
|
rv = names[:]
|
2020-07-24 17:37:32 +00:00
|
|
|
for pattern in to_skip:
|
2016-06-15 19:07:42 +00:00
|
|
|
rv = [n for n in rv if not fnmatch.fnmatch(n, pattern)]
|
|
|
|
return rv
|
|
|
|
|
|
|
|
|
2020-07-24 17:37:32 +00:00
|
|
|
def zip(target_dir, zip_file, to_skip=None): # pylint: disable=W0622
|
2016-06-15 19:07:42 +00:00
|
|
|
"""Zip the given directory, write to the given zip file."""
|
|
|
|
if not os.path.isdir(target_dir):
|
|
|
|
raise IOError('%s does not exist!' % target_dir)
|
2020-07-24 17:37:32 +00:00
|
|
|
to_skip = to_skip or []
|
2016-08-26 17:52:19 +00:00
|
|
|
with zipfile.ZipFile(zip_file, 'w', zipfile.ZIP_DEFLATED, True) as z:
|
2016-06-15 19:07:42 +00:00
|
|
|
for r, d, f in os.walk(target_dir, topdown=True):
|
2020-07-24 17:37:32 +00:00
|
|
|
d[:] = filtered(d, to_skip)
|
|
|
|
for filename in filtered(f, to_skip):
|
2016-06-15 19:07:42 +00:00
|
|
|
filepath = os.path.join(r, filename)
|
|
|
|
zi = zipfile.ZipInfo(filepath)
|
|
|
|
zi.filename = os.path.relpath(filepath, target_dir)
|
2017-09-28 16:31:32 +00:00
|
|
|
if os.name == 'nt':
|
|
|
|
# Dumb path separator replacement for Windows.
|
|
|
|
zi.filename = zi.filename.replace(ntpath.sep, posixpath.sep)
|
2018-09-27 18:55:03 +00:00
|
|
|
try:
|
|
|
|
perms = os.stat(filepath).st_mode
|
|
|
|
except OSError:
|
|
|
|
if os.path.islink(filepath):
|
2021-03-25 13:04:43 +00:00
|
|
|
print('Skipping symlink %s' % filepath)
|
2018-09-27 18:55:03 +00:00
|
|
|
continue
|
|
|
|
else:
|
|
|
|
raise
|
2021-03-25 13:04:43 +00:00
|
|
|
zi.external_attr = perms << 16
|
2016-08-26 17:52:19 +00:00
|
|
|
zi.compress_type = zipfile.ZIP_DEFLATED
|
2016-06-15 19:07:42 +00:00
|
|
|
with open(filepath, 'rb') as f:
|
|
|
|
content = f.read()
|
|
|
|
z.writestr(zi, content)
|
|
|
|
for dirname in d:
|
|
|
|
dirpath = os.path.join(r, dirname)
|
|
|
|
z.write(dirpath, os.path.relpath(dirpath, target_dir))
|
|
|
|
|
|
|
|
|
|
|
|
def unzip(zip_file, target_dir):
|
|
|
|
"""Unzip the given zip file into the target dir."""
|
|
|
|
if not os.path.isdir(target_dir):
|
|
|
|
os.makedirs(target_dir)
|
2016-08-26 17:52:19 +00:00
|
|
|
with zipfile.ZipFile(zip_file, 'r', zipfile.ZIP_DEFLATED, True) as z:
|
2016-06-15 19:07:42 +00:00
|
|
|
for zi in z.infolist():
|
2017-09-28 16:31:32 +00:00
|
|
|
dst_subpath = zi.filename
|
|
|
|
if os.name == 'nt':
|
|
|
|
# Dumb path separator replacement for Windows.
|
|
|
|
dst_subpath = dst_subpath.replace(posixpath.sep, ntpath.sep)
|
|
|
|
dst_path = os.path.join(target_dir, dst_subpath)
|
|
|
|
if dst_path.endswith(os.path.sep):
|
2016-06-15 19:07:42 +00:00
|
|
|
os.mkdir(dst_path)
|
|
|
|
else:
|
2016-10-31 19:28:10 +00:00
|
|
|
with open(dst_path, 'wb') as f:
|
2016-06-15 19:07:42 +00:00
|
|
|
f.write(z.read(zi))
|
2021-03-25 13:04:43 +00:00
|
|
|
perms = zi.external_attr >> 16
|
2016-06-15 19:07:42 +00:00
|
|
|
os.chmod(dst_path, perms)
|