Add an altered version of the code contributed by Bjorn Gruning to support installation of tool dependencies that are zip archives when installing repositories from the tool shed. Bjorn's initial code required Python 2.6, so change ser made to support Python 2.5+.

This commit is contained in:
Greg Von Kuster
2012-10-25 11:54:07 -04:00
parent 3cd23b2c25
commit 2cd22e4f1a
3 changed files with 44 additions and 6 deletions
@@ -1,12 +1,24 @@
import os, shutil, tarfile, urllib2
import os, shutil, tarfile, urllib2, zipfile
from galaxy.datatypes.checkers import *
def zipfile_ok( path_to_archive ):
"""
This function is a bit pedantic and not functionally necessary. It checks whether there is no file pointing outside of the extraction,
because ZipFile.extractall() has some potential security holes. See python zipfile documentation for more details.
"""
basename = os.path.realpath( os.path.dirname( path_to_archive ) )
zip_archive = zipfile.ZipFile( path_to_archive )
for member in zip_archive.namelist():
member_path = os.path.realpath( os.path.join( basename, member ) )
if not member_path.startswith( basename ):
return False
return True
def create_env_var_dict( elem, tool_dependency_install_dir=None, tool_shed_repository_install_dir=None ):
env_var_name = elem.get( 'name', 'PATH' )
env_var_action = elem.get( 'action', 'prepend_to' )
env_var_text = None
if elem.text and elem.text.find( 'REPOSITORY_INSTALL_DIR' ) >= 0:
if tool_shed_repository_install_dir:
if tool_shed_repository_install_dir and elem.text.find( '$REPOSITORY_INSTALL_DIR' ) != -1:
env_var_text = elem.text.replace( '$REPOSITORY_INSTALL_DIR', tool_shed_repository_install_dir )
return dict( name=env_var_name, action=env_var_action, value=env_var_text )
else:
@@ -50,6 +62,20 @@ def extract_tar( file_name, file_path ):
tar = tarfile.open( file_name )
tar.extractall( path=file_path )
tar.close()
def extract_zip( archive_path, extraction_path ):
# TODO: change this method to use zipfile.Zipfile.extractall() when we stop supporting Python 2.5.
if not zipfile_ok( archive_path ):
return False
zip_archive = zipfile.ZipFile( archive_path, 'r' )
for name in zip_archive.namelist():
uncompressed_path = os.path.join( extraction_path, name )
if uncompressed_path.endswith( '/' ):
if not os.path.isdir( uncompressed_path ):
os.makedirs( uncompressed_path )
else:
file( uncompressed_path, 'wb' ).write( zip_archive.read( name ) )
zip_archive.close()
return True
def isbz2( file_path ):
return is_bz2( file_path )
def isgzip( file_path ):
@@ -102,3 +128,13 @@ def url_download( install_dir, downloaded_file_name, download_url ):
if dst:
dst.close()
return os.path.abspath( file_path )
def zip_extraction_directory( file_path, file_name ):
"""Try to return the correct extraction directory."""
files = [ filename for filename in os.listdir( file_path ) if not filename.endswith( '.zip' ) ]
if len( files ) > 1:
return os.path.abspath( file_path )
elif len( files ) == 1:
# If there is only on file it should be a directory.
if os.path.isdir( os.path.join( file_path, files[ 0 ] ) ):
return os.path.abspath( os.path.join( file_path, files[ 0 ] ) )
raise ValueError( 'Could not find directory for the extracted file %s' % os.path.abspath( os.path.join( file_path, file_name ) ) )
@@ -49,8 +49,6 @@ def install_and_build_package( app, tool_dependency, actions_dict ):
sa_session = app.model.context.current
install_dir = actions_dict[ 'install_dir' ]
package_name = actions_dict[ 'package_name' ]
#download_url = actions_dict.get( 'download_url', None )
#clone_cmd = actions_dict.get( 'clone_cmd', None )
actions = actions_dict.get( 'actions', None )
if actions:
with make_tmp_dir() as work_dir:
@@ -59,13 +57,17 @@ def install_and_build_package( app, tool_dependency, actions_dict ):
# are currently only two supported processes; download_by_url and clone via a "shell_command" action type.
action_type, action_dict = actions[ 0 ]
if action_type == 'download_by_url':
# <action type="download_by_url">http://sourceforge.net/projects/samtools/files/samtools/0.1.18/samtools-0.1.18.tar.bz2</action>
url = action_dict[ 'url' ]
downloaded_filename = os.path.split( url )[ -1 ]
downloaded_file_path = common_util.url_download( work_dir, downloaded_filename, url )
if common_util.istar( downloaded_file_path ):
# <action type="download_by_url">http://sourceforge.net/projects/samtools/files/samtools/0.1.18/samtools-0.1.18.tar.bz2</action>
common_util.extract_tar( downloaded_file_path, work_dir )
dir = common_util.tar_extraction_directory( work_dir, downloaded_filename )
elif common_util.iszip( downloaded_file_path ):
# <action type="download_by_url">http://downloads.sourceforge.net/project/picard/picard-tools/1.56/picard-tools-1.56.zip</action>
zip_archive_extracted = common_util.extract_zip( downloaded_file_path, work_dir )
dir = common_util.zip_extraction_directory( work_dir, downloaded_filename )
else:
dir = work_dir
elif action_type == 'shell_command':
@@ -58,7 +58,7 @@
${tool_dependency.status}
<div style="clear: both"></div>
</div>
%if repository.in_error_state:
%if tool_dependency.in_error_state:
<div class="form-row" >
<label>Tool dependency installation error:</label>
${tool_dependency.error_message}