Commit 30ad6e2c authored by Serhiy Storchaka's avatar Serhiy Storchaka

Issue #14061: Misc fixes and cleanups in archiving code in shutil.

Improved the documentation and tests for make_archive().
Improved error handling when corresponding compress module is not available.
External zip executable is now used if the zlib module is not available.
parent 6560e22c
......@@ -267,7 +267,9 @@ provided. They rely on the :mod:`zipfile` and :mod:`tarfile` modules.
*base_name* is the name of the file to create, including the path, minus
any format-specific extension. *format* is the archive format: one of
"zip", "tar", "bztar" or "gztar".
"zip" (if the :mod:`zlib` module or external ``zip`` executable is
available), "tar", "gztar" (if the :mod:`zlib` module is available), or
"bztar" (if the :mod:`bz2` module is available).
*root_dir* is a directory that will be the root directory of the
archive; ie. we typically chdir into *root_dir* before creating the
......@@ -295,10 +297,11 @@ provided. They rely on the :mod:`zipfile` and :mod:`tarfile` modules.
By default :mod:`shutil` provides these formats:
- *gztar*: gzip'ed tar-file
- *bztar*: bzip2'ed tar-file
- *tar*: uncompressed tar file
- *zip*: ZIP file
- *zip*: ZIP file (if the :mod:`zlib` module or external ``zip``
executable is available).
- *tar*: uncompressed tar file.
- *gztar*: gzip'ed tar-file (if the :mod:`zlib` module is available).
- *bztar*: bzip2'ed tar-file (if the :mod:`bz2` module is available).
You can register new formats or provide your own archiver for any existing
formats, by using :func:`register_archive_format`.
......
......@@ -12,6 +12,20 @@ import fnmatch
import collections
import errno
try:
import zlib
del zlib
_ZLIB_SUPPORTED = True
except ImportError:
_ZLIB_SUPPORTED = False
try:
import bz2
del bz2
_BZ2_SUPPORTED = True
except ImportError:
_BZ2_SUPPORTED = False
try:
from pwd import getpwnam
except ImportError:
......@@ -351,15 +365,18 @@ def _make_tarball(base_name, base_dir, compress="gzip", verbose=0, dry_run=0,
Returns the output filename.
"""
tar_compression = {'gzip': 'gz', 'bzip2': 'bz2', None: ''}
compress_ext = {'gzip': '.gz', 'bzip2': '.bz2'}
# flags for compression program, each element of list will be an argument
if compress is not None and compress not in compress_ext.keys():
raise ValueError, \
("bad value for 'compress': must be None, 'gzip' or 'bzip2'")
if compress is None:
tar_compression = ''
elif _ZLIB_SUPPORTED and compress == 'gzip':
tar_compression = 'gz'
elif _BZ2_SUPPORTED and compress == 'bzip2':
tar_compression = 'bz2'
else:
raise ValueError("bad value for 'compress', or compression format not "
"supported : {0}".format(compress))
archive_name = base_name + '.tar' + compress_ext.get(compress, '')
compress_ext = '.' + tar_compression if compress else ''
archive_name = base_name + '.tar' + compress_ext
archive_dir = os.path.dirname(archive_name)
if archive_dir and not os.path.exists(archive_dir):
......@@ -388,7 +405,7 @@ def _make_tarball(base_name, base_dir, compress="gzip", verbose=0, dry_run=0,
return tarinfo
if not dry_run:
tar = tarfile.open(archive_name, 'w|%s' % tar_compression[compress])
tar = tarfile.open(archive_name, 'w|%s' % tar_compression)
try:
tar.add(base_dir, filter=_set_uid_gid)
finally:
......@@ -435,6 +452,7 @@ def _make_zipfile(base_name, base_dir, verbose=0, dry_run=0, logger=None):
# If zipfile module is not available, try spawning an external 'zip'
# command.
try:
import zlib
import zipfile
except ImportError:
zipfile = None
......@@ -470,11 +488,17 @@ def _make_zipfile(base_name, base_dir, verbose=0, dry_run=0, logger=None):
return zip_filename
_ARCHIVE_FORMATS = {
'gztar': (_make_tarball, [('compress', 'gzip')], "gzip'ed tar-file"),
'bztar': (_make_tarball, [('compress', 'bzip2')], "bzip2'ed tar-file"),
'tar': (_make_tarball, [('compress', None)], "uncompressed tar file"),
'zip': (_make_zipfile, [],"ZIP file")
}
'zip': (_make_zipfile, [], "ZIP file")
}
if _ZLIB_SUPPORTED:
_ARCHIVE_FORMATS['gztar'] = (_make_tarball, [('compress', 'gzip')],
"gzip'ed tar-file")
if _BZ2_SUPPORTED:
_ARCHIVE_FORMATS['bztar'] = (_make_tarball, [('compress', 'bzip2')],
"bzip2'ed tar-file")
def get_archive_formats():
"""Returns a list of supported formats for archiving and unarchiving.
......@@ -515,8 +539,8 @@ def make_archive(base_name, format, root_dir=None, base_dir=None, verbose=0,
"""Create an archive file (eg. zip or tar).
'base_name' is the name of the file to create, minus any format-specific
extension; 'format' is the archive format: one of "zip", "tar", "bztar"
or "gztar".
extension; 'format' is the archive format: one of "zip", "tar", "gztar",
or "bztar". Or any other registered format.
'root_dir' is a directory that will be the root directory of the
archive; ie. we typically chdir into 'root_dir' before creating the
......
......@@ -35,6 +35,7 @@ except ImportError:
try:
import zipfile
import zlib
ZIP_SUPPORT = True
except ImportError:
ZIP_SUPPORT = find_executable('zip')
......@@ -460,7 +461,6 @@ class TestShutil(unittest.TestCase):
self.assertEqual(tarball, base_name + '.tar')
self.assertTrue(os.path.isfile(tarball))
@unittest.skipUnless(zlib, "Requires zlib")
@unittest.skipUnless(ZIP_SUPPORT, 'Need zip support to run')
def test_make_zipfile(self):
# creating something to zip
......@@ -485,6 +485,7 @@ class TestShutil(unittest.TestCase):
['dist/', 'dist/file1', 'dist/file2',
'dist/sub/', 'dist/sub/file3', 'dist/sub2/',
'outer'])
support.unlink(res)
with support.change_cwd(work_dir):
base_name = os.path.abspath(rel_base_name)
......@@ -498,7 +499,6 @@ class TestShutil(unittest.TestCase):
['dist/', 'dist/file1', 'dist/file2',
'dist/sub/', 'dist/sub/file3', 'dist/sub2/'])
@unittest.skipUnless(zlib, "Requires zlib")
@unittest.skipUnless(ZIP_SUPPORT, 'Need zip support to run')
@unittest.skipUnless(find_executable('zip'),
'Need the zip command to run')
......@@ -524,7 +524,6 @@ class TestShutil(unittest.TestCase):
names2 = zf.namelist()
self.assertEqual(sorted(names), sorted(names2))
@unittest.skipUnless(zlib, "Requires zlib")
@unittest.skipUnless(ZIP_SUPPORT, 'Need zip support to run')
@unittest.skipUnless(find_executable('unzip'),
'Need the unzip command to run')
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment