commit/galaxy-central: greg: 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+.
1 new commit in galaxy-central: https://bitbucket.org/galaxy/galaxy-central/changeset/b12140970208/ changeset: b12140970208 user: greg date: 2012-10-25 17:54:07 summary: 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+. affected #: 3 files diff -r 6641f66fdafd6684deda5c8d132c28491c5d39c7 -r b121409702081725920cec548eea991b1bbe6a6f lib/galaxy/tool_shed/tool_dependencies/common_util.py --- a/lib/galaxy/tool_shed/tool_dependencies/common_util.py +++ b/lib/galaxy/tool_shed/tool_dependencies/common_util.py @@ -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 @@ 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 @@ 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 ) ) ) diff -r 6641f66fdafd6684deda5c8d132c28491c5d39c7 -r b121409702081725920cec548eea991b1bbe6a6f lib/galaxy/tool_shed/tool_dependencies/fabric_util.py --- a/lib/galaxy/tool_shed/tool_dependencies/fabric_util.py +++ b/lib/galaxy/tool_shed/tool_dependencies/fabric_util.py @@ -49,8 +49,6 @@ 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 @@ # 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': diff -r 6641f66fdafd6684deda5c8d132c28491c5d39c7 -r b121409702081725920cec548eea991b1bbe6a6f templates/admin/tool_shed_repository/browse_tool_dependency.mako --- a/templates/admin/tool_shed_repository/browse_tool_dependency.mako +++ b/templates/admin/tool_shed_repository/browse_tool_dependency.mako @@ -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} Repository URL: https://bitbucket.org/galaxy/galaxy-central/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email.
participants (1)
-
Bitbucket