Merge pull request #10072 from dannon/fix-library-zip-download

Fix library zip download
This commit is contained in:
Björn Grüning
2020-08-06 15:02:11 +02:00
committed by GitHub
3 changed files with 36 additions and 29 deletions
+4 -3
View File
@@ -47,12 +47,13 @@ class ZipBall:
def __init__(self, tmpf, tmpd):
self._tmpf = tmpf
self._tmpd = tmpd
self.wsgi_status = None
self.wsgi_headeritems = None
def stream(self, environ, start_response):
response_write = start_response(self.wsgi_status, self.wsgi_headeritems)
tmpfh = open(self._tmpf)
response_write(tmpfh.read())
tmpfh.close()
with open(self._tmpf, 'rb') as tmpfh:
response_write(tmpfh.read())
try:
os.unlink(self._tmpf)
os.rmdir(self._tmpd)
@@ -42,11 +42,6 @@ from galaxy.webapps.base.controller import (
UsesVisualizationMixin,
)
try:
maketrans = str.maketrans
except AttributeError:
from string import maketrans
log = logging.getLogger(__name__)
@@ -512,19 +507,19 @@ class LibraryDatasetsController(BaseAPIController, UsesVisualizationMixin, Libra
@web.expose
# TODO convert to expose_api
def download(self, trans, format, **kwd):
def download(self, trans, archive_format, **kwd):
"""
GET /api/libraries/datasets/download/{format}
POST /api/libraries/datasets/download/{format}
GET /api/libraries/datasets/download/{archive_format}
POST /api/libraries/datasets/download/{archive_format}
Download requested datasets (identified by encoded IDs) in requested format.
Download requested datasets (identified by encoded IDs) in requested archive_format.
example: ``GET localhost:8080/api/libraries/datasets/download/tbz?ld_ids%255B%255D=a0d84b45643a2678&ld_ids%255B%255D=fe38c84dcd46c828``
.. note:: supported format values are: 'zip', 'tgz', 'tbz', 'uncompressed'
.. note:: supported archive_format values are: 'zip', 'tgz', 'tbz', 'uncompressed'
:param format: string representing requested archive format
:type format: string
:param archive_format: string representing requested archive archive_format
:type archive_format: string
:param ld_ids[]: an array of encoded dataset ids
:type ld_ids[]: an array
:param folder_ids[]: an array of encoded folder ids
@@ -586,30 +581,41 @@ class LibraryDatasetsController(BaseAPIController, UsesVisualizationMixin, Libra
if not library_datasets:
raise exceptions.RequestParameterMissingException('Request has to contain a list of dataset ids or folder ids to download.')
if format in ['zip', 'tgz', 'tbz']:
if archive_format in ['zip', 'tgz', 'tbz']:
# error = False
killme = string.punctuation + string.whitespace
trantab = maketrans(killme, '_' * len(killme))
trantab = str.maketrans(killme, '_' * len(killme))
try:
outext = 'zip'
if format == 'zip':
if archive_format == 'zip':
# Can't use mkstemp - the file must not exist first
tmpd = tempfile.mkdtemp()
util.umask_fix_perms(tmpd, trans.app.config.umask, 0o777, self.app.config.gid)
tmpf = os.path.join(tmpd, 'library_download.' + format)
tmpf = os.path.join(tmpd, 'library_download.' + archive_format)
if trans.app.config.upstream_gzip:
archive = zipfile.ZipFile(tmpf, 'w', zipfile.ZIP_STORED, True)
else:
archive = zipfile.ZipFile(tmpf, 'w', zipfile.ZIP_DEFLATED, True)
archive.add = lambda x, y: archive.write(x, y.encode('CP437'))
elif format == 'tgz':
def zipfile_add(fpath, arcname):
encoded_arcname = arcname.encode('CP437')
try:
archive.write(fpath, encoded_arcname)
except TypeError:
# Despite documenting the need for CP437 encoded arcname,
# python 3 actually needs this to be a unicode string ...
# https://bugs.python.org/issue24110
archive.write(fpath, arcname)
archive.add = zipfile_add
elif archive_format == 'tgz':
if trans.app.config.upstream_gzip:
archive = StreamBall('w|')
outext = 'tar'
else:
archive = StreamBall('w|gz')
outext = 'tgz'
elif format == 'tbz':
elif archive_format == 'tbz':
archive = StreamBall('w|bz2')
outext = 'tbz2'
except (OSError, zipfile.BadZipfile):
@@ -646,7 +652,7 @@ class LibraryDatasetsController(BaseAPIController, UsesVisualizationMixin, Libra
if zpathext == '':
zpath = '%s.html' % zpath # fake the real nature of the html file
try:
if format == 'zip':
if archive_format == 'zip':
archive.add(ldda.dataset.file_name, zpath) # add the primary of a composite set
else:
archive.add(ldda.dataset.file_name, zpath, check_file=True) # add the primary of a composite set
@@ -666,7 +672,7 @@ class LibraryDatasetsController(BaseAPIController, UsesVisualizationMixin, Libra
if fname > '':
fname = fname.translate(trantab)
try:
if format == 'zip':
if archive_format == 'zip':
archive.add(fpath, fname)
else:
archive.add(fpath, fname, check_file=True)
@@ -681,7 +687,7 @@ class LibraryDatasetsController(BaseAPIController, UsesVisualizationMixin, Libra
raise exceptions.InternalServerError("Unable to add dataset to temporary library download archive . " + util.unicodify(e))
else:
try:
if format == 'zip':
if archive_format == 'zip':
archive.add(ldda.dataset.file_name, path)
else:
archive.add(ldda.dataset.file_name, path, check_file=True)
@@ -696,7 +702,7 @@ class LibraryDatasetsController(BaseAPIController, UsesVisualizationMixin, Libra
raise exceptions.InternalServerError("Unknown error. " + util.unicodify(e))
lname = 'selected_dataset'
fname = lname.replace(' ', '_') + '_files'
if format == 'zip':
if archive_format == 'zip':
archive.close()
trans.response.set_content_type("application/octet-stream")
trans.response.headers["Content-Disposition"] = 'attachment; filename="{}.{}"'.format(fname, outext)
@@ -710,7 +716,7 @@ class LibraryDatasetsController(BaseAPIController, UsesVisualizationMixin, Libra
archive.wsgi_status = trans.response.wsgi_status()
archive.wsgi_headeritems = trans.response.wsgi_headeritems()
return archive.stream
elif format == 'uncompressed':
elif archive_format == 'uncompressed':
if len(library_datasets) != 1:
raise exceptions.RequestParameterInvalidException("You can download only one uncompressed file at once.")
else:
@@ -728,4 +734,4 @@ class LibraryDatasetsController(BaseAPIController, UsesVisualizationMixin, Libra
except Exception:
raise exceptions.InternalServerError("This dataset contains no content.")
else:
raise exceptions.RequestParameterInvalidException("Wrong format parameter specified")
raise exceptions.RequestParameterInvalidException("Wrong archive_format parameter specified")
+1 -1
View File
@@ -869,7 +869,7 @@ def populate_api_routes(webapp, app):
conditions=dict(method=["DELETE"]))
webapp.mapper.connect('download_ld_items',
'/api/libraries/datasets/download/{format}',
'/api/libraries/datasets/download/{archive_format}',
controller='library_datasets',
action='download',
conditions=dict(method=["POST", "GET"]))