Commit e3e15b9f authored by Kazuhiko Shiozaki's avatar Kazuhiko Shiozaki

downloadunpacked: extract symlinks in a tar archive as symlinks.

parent af85beec
......@@ -27,6 +27,7 @@
import os
import logging
import shutil
import tarfile
import zc.buildout
import tempfile
import setuptools
......@@ -80,7 +81,11 @@ class Recipe:
md5sum=self.options.get('md5sum'))
extract_dir = tempfile.mkdtemp(self.name)
self.logger.debug('Created working directory %r' % extract_dir)
setuptools.archive_util.unpack_archive(path, extract_dir)
try:
patch_archive_util()
setuptools.archive_util.unpack_archive(path, extract_dir)
finally:
unpatch_archive_util()
# Delete destination directory if exist
if os.path.exists(self.destination):
......@@ -112,3 +117,53 @@ class Recipe:
def update(self):
pass
# Monkey patch to keep symlinks in tarfile
def unpack_tarfile_patched(filename, extract_dir, progress_filter=setuptools.archive_util.default_filter):
"""Unpack tar/tar.gz/tar.bz2 `filename` to `extract_dir`
Raises ``UnrecognizedFormat`` if `filename` is not a tarfile (as determined
by ``tarfile.open()``). See ``unpack_archive()`` for an explanation
of the `progress_filter` argument.
"""
try:
tarobj = tarfile.open(filename)
except tarfile.TarError:
raise setuptools.archive_util.UnrecognizedFormat(
"%s is not a compressed or uncompressed tar file" % (filename,)
)
with setuptools.archive_util.contextlib.closing(tarobj):
# don't do any chowning!
tarobj.chown = lambda *args: None
for member in tarobj:
name = member.name
# don't extract absolute paths or ones with .. in them
if not name.startswith('/') and '..' not in name.split('/'):
prelim_dst = os.path.join(extract_dir, *name.split('/'))
if member is not None and (member.isfile() or member.isdir() or member.islnk() or member.issym()):
final_dst = progress_filter(name, prelim_dst)
if final_dst:
if final_dst.endswith(os.sep):
final_dst = final_dst[:-1]
try:
# XXX Ugh
tarobj._extract_member(member, final_dst)
except tarfile.ExtractError:
# chown/chmod/mkfifo/mknode/makedev failed
pass
return True
def patch_archive_util():
setuptools.archive_util.extraction_drivers = (
setuptools.archive_util.unpack_directory,
setuptools.archive_util.unpack_zipfile,
unpack_tarfile_patched,
)
def unpatch_archive_util():
setuptools.archive_util.extraction_drivers = (
setuptools.archive_util.unpack_directory,
setuptools.archive_util.unpack_zipfile,
setuptools.archive_util.unpack_tarfile,
)
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