Files
mayan-edms/mayan/apps/common/compressed_files.py
Roberto Rosario 36a51eeb73 Switch to full app paths
Instead of inserting the path of the apps into the Python app,
the apps are now referenced by their full import path.

This solves name clashes with external or native Python libraries.
Example: Mayan statistics app vs. Python new statistics library.

Every app reference is now prepended with 'mayan.apps'.

Existing config.yml files need to be updated manually.

Signed-off-by: Roberto Rosario <roberto.rosario.gonzalez@gmail.com>
2019-04-05 02:02:57 -04:00

175 lines
4.7 KiB
Python

from __future__ import unicode_literals
from io import BytesIO
import tarfile
import zipfile
try:
import zlib # NOQA
COMPRESSION = zipfile.ZIP_DEFLATED
except ImportError:
COMPRESSION = zipfile.ZIP_STORED
from django.core.files.uploadedfile import SimpleUploadedFile
from mayan.apps.mimetype.api import get_mimetype
from .exceptions import NoMIMETypeMatch
class Archive(object):
_registry = {}
@classmethod
def register(cls, mime_types, archive_classes):
for mime_type in mime_types:
for archive_class in archive_classes:
cls._registry.setdefault(
mime_type, []
).append(archive_class)
@classmethod
def open(cls, file_object):
mime_type = get_mimetype(
file_object=file_object, mimetype_only=True
)[0]
try:
for archive_class in cls._registry[mime_type]:
instance = archive_class()
instance._open(file_object=file_object)
return instance
except KeyError:
raise NoMIMETypeMatch
def _open(self, file_object):
raise NotImplementedError
def add_file(self, file_object, filename):
"""
Add a file as a member of an archive
"""
raise NotImplementedError
def close(self):
self._archive.close()
def create(self):
"""
Create an empty archive
"""
raise NotImplementedError
def get_members(self):
return (
SimpleUploadedFile(
name=filename, content=self.member_contents(filename)
) for filename in self.members()
)
def member_contents(self, filename):
"""
Return the content of a member
"""
raise NotImplementedError
def members(self):
"""
Return a list of all the elements inside the archive
"""
raise NotImplementedError
def open_member(self, filename):
"""
Return a file-like object to a member of the archive
"""
raise NotImplemented
class TarArchive(Archive):
def _open(self, file_object):
self._archive = tarfile.open(fileobj=file_object)
def add_file(self, file_object, filename):
self._archive.addfile(
tarfile.TarInfo(), fileobj=file_object
)
def create(self):
self.string_buffer = BytesIO()
self._archive = tarfile.TarFile(fileobj=self.string_buffer, mode='w')
def member_contents(self, filename):
return self._archive.extractfile(filename).read()
def members(self):
return self._archive.getnames()
def open_member(self, filename):
return self._archive.extractfile(filename)
class ZipArchive(Archive):
def _open(self, file_object):
self._archive = zipfile.ZipFile(file_object)
def add_file(self, file_object, filename):
# Remove the zinfo_or_arcname and bytes keyword arguments
# so that the writestr methods works on Python 2 and 3
# Python 2 syntax:
# ZipFile.writestr(zinfo_or_arcname, bytes[, compress_type])
# Python 3 syntax:
# ZipFile.writestr(
# zinfo_or_arcname, data, compress_type=None, compresslevel=None
# )
# TODO: Change this to keyword arguments when the move to Python 3
# and Django 2.x is complete.
self._archive.writestr(
filename, file_object.read(), compress_type=COMPRESSION
)
def create(self):
self.string_buffer = BytesIO()
self._archive = zipfile.ZipFile(self.string_buffer, mode='w')
def member_contents(self, filename):
return self._archive.read(filename)
def members(self):
return [
filename for filename in self._archive.namelist() if not filename.endswith('/')
]
def open_member(self, filename):
return self._archive.open(filename)
def write(self, filename=None):
# fix for Linux zip files read in Windows
for entry in self._archive.filelist:
entry.create_system = 0
self.string_buffer.seek(0)
if filename:
with open(filename, 'w') as file_object:
file_object.write(self.string_buffer.read())
else:
return self.string_buffer
def as_file(self, filename):
return SimpleUploadedFile(name=filename, content=self.write().read())
Archive.register(
mime_types=('application/zip',), archive_classes=(ZipArchive,)
)
Archive.register(
mime_types=('application/x-tar',), archive_classes=(TarArchive,)
)
Archive.register(
mime_types=('application/gzip',), archive_classes=(TarArchive,)
)
Archive.register(
mime_types=('application/x-bzip2',), archive_classes=(TarArchive,)
)