PageRenderTime 48ms CodeModel.GetById 16ms RepoModel.GetById 1ms app.codeStats 0ms

/lib/tool_shed/galaxy_install/tool_dependencies/fabric_util.py

https://bitbucket.org/james_taylor/galaxy-central
Python | 175 lines | 142 code | 9 blank | 24 comment | 30 complexity | e53c634afec6e91142b0e52a69b1f82c MD5 | raw file
Possible License(s): CC-BY-3.0
  1. # For Python 2.5
  2. from __future__ import with_statement
  3. import common_util
  4. import logging
  5. import os
  6. import shutil
  7. import tempfile
  8. from contextlib import contextmanager
  9. from galaxy import eggs
  10. import pkg_resources
  11. pkg_resources.require('ssh' )
  12. pkg_resources.require( 'Fabric' )
  13. from fabric.api import env
  14. from fabric.api import lcd
  15. from fabric.api import local
  16. from fabric.api import settings
  17. log = logging.getLogger( __name__ )
  18. INSTALLATION_LOG = 'INSTALLATION.log'
  19. def check_fabric_version():
  20. version = env.version
  21. if int( version.split( "." )[ 0 ] ) < 1:
  22. raise NotImplementedError( "Install Fabric version 1.0 or later." )
  23. def handle_command( app, tool_dependency, install_dir, cmd ):
  24. sa_session = app.model.context.current
  25. output = local( cmd, capture=True )
  26. log_results( cmd, output, os.path.join( install_dir, INSTALLATION_LOG ) )
  27. if output.return_code:
  28. tool_dependency.status = app.model.ToolDependency.installation_status.ERROR
  29. if output.stderr:
  30. tool_dependency.error_message = str( output.stderr )[ :32768 ]
  31. elif output.stdout:
  32. tool_dependency.error_message = str( output.stdout )[ :32768 ]
  33. else:
  34. tool_dependency.error_message = "Unknown error occurred executing shell command %s, return_code: %s" % ( str( cmd ), str( output.return_code ) )
  35. sa_session.add( tool_dependency )
  36. sa_session.flush()
  37. return output.return_code
  38. def install_and_build_package( app, tool_dependency, actions_dict ):
  39. """Install a Galaxy tool dependency package either via a url or a mercurial or git clone command."""
  40. sa_session = app.model.context.current
  41. install_dir = actions_dict[ 'install_dir' ]
  42. package_name = actions_dict[ 'package_name' ]
  43. actions = actions_dict.get( 'actions', None )
  44. filtered_actions = []
  45. env_shell_file_paths = []
  46. if actions:
  47. with make_tmp_dir() as work_dir:
  48. with lcd( work_dir ):
  49. # The first action in the list of actions will be the one that defines the installation process. There
  50. # are currently only two supported processes; download_by_url and clone via a "shell_command" action type.
  51. action_type, action_dict = actions[ 0 ]
  52. if action_type == 'download_by_url':
  53. # Eliminate the download_by_url action so remaining actions can be processed correctly.
  54. filtered_actions = actions[ 1: ]
  55. url = action_dict[ 'url' ]
  56. if 'target_filename' in action_dict:
  57. downloaded_filename = action_dict[ 'target_filename' ]
  58. else:
  59. downloaded_filename = os.path.split( url )[ -1 ]
  60. downloaded_file_path = common_util.url_download( work_dir, downloaded_filename, url )
  61. if common_util.istar( downloaded_file_path ):
  62. # <action type="download_by_url">http://sourceforge.net/projects/samtools/files/samtools/0.1.18/samtools-0.1.18.tar.bz2</action>
  63. common_util.extract_tar( downloaded_file_path, work_dir )
  64. dir = common_util.tar_extraction_directory( work_dir, downloaded_filename )
  65. elif common_util.iszip( downloaded_file_path ):
  66. # <action type="download_by_url">http://downloads.sourceforge.net/project/picard/picard-tools/1.56/picard-tools-1.56.zip</action>
  67. zip_archive_extracted = common_util.extract_zip( downloaded_file_path, work_dir )
  68. dir = common_util.zip_extraction_directory( work_dir, downloaded_filename )
  69. else:
  70. dir = os.path.curdir
  71. elif action_type == 'shell_command':
  72. # <action type="shell_command">git clone --recursive git://github.com/ekg/freebayes.git</action>
  73. # Eliminate the shell_command clone action so remaining actions can be processed correctly.
  74. filtered_actions = actions[ 1: ]
  75. return_code = handle_command( app, tool_dependency, install_dir, action_dict[ 'command' ] )
  76. if return_code:
  77. return
  78. dir = package_name
  79. else:
  80. # We're handling a complex repository dependency where we only have a set_environment tag set.
  81. # <action type="set_environment">
  82. # <environment_variable name="PATH" action="prepend_to">$INSTALL_DIR/bin</environment_variable>
  83. # </action>
  84. filtered_actions = [ a for a in actions ]
  85. dir = install_dir
  86. # We need to be careful in determining if the value of dir is a valid directory because we're dealing with 2 environments, the fabric local
  87. # environment and the python environment. Checking the path as follows should work.
  88. full_path_to_dir = os.path.abspath( os.path.join( work_dir, dir ) )
  89. if not os.path.exists( full_path_to_dir ):
  90. os.makedirs( full_path_to_dir )
  91. # The package has been down-loaded, so we can now perform all of the actions defined for building it.
  92. with lcd( dir ):
  93. for action_tup in filtered_actions:
  94. action_type, action_dict = action_tup
  95. current_dir = os.path.abspath( os.path.join( work_dir, dir ) )
  96. if action_type == 'make_directory':
  97. common_util.make_directory( full_path=action_dict[ 'full_path' ] )
  98. elif action_type == 'move_directory_files':
  99. common_util.move_directory_files( current_dir=current_dir,
  100. source_dir=os.path.join( action_dict[ 'source_directory' ] ),
  101. destination_dir=os.path.join( action_dict[ 'destination_directory' ] ) )
  102. elif action_type == 'move_file':
  103. # TODO: Remove this hack that resets current_dir so that the pre-compiled bwa binary can be found.
  104. # current_dir = '/Users/gvk/workspaces_2008/bwa/bwa-0.5.9'
  105. common_util.move_file( current_dir=current_dir,
  106. source=os.path.join( action_dict[ 'source' ] ),
  107. destination_dir=os.path.join( action_dict[ 'destination' ] ) )
  108. elif action_type == 'set_environment':
  109. # Currently the only action supported in this category is "environment_variable".
  110. env_var_dicts = action_dict[ 'environment_variable' ]
  111. for env_var_dict in env_var_dicts:
  112. cmd = common_util.create_or_update_env_shell_file( install_dir, env_var_dict )
  113. return_code = handle_command( app, tool_dependency, install_dir, cmd )
  114. if return_code:
  115. return
  116. elif action_type == 'set_environment_for_install':
  117. # Currently the only action supported in this category is a list of paths to one or more tool dependency env.sh files,
  118. # the environment setting in each of which will be injected into the environment for all <action type="shell_command">
  119. # tags that follow this <action type="set_environment_for_install"> tag set in the tool_dependencies.xml file.
  120. env_shell_file_paths = action_dict[ 'env_shell_file_paths' ]
  121. elif action_type == 'shell_command':
  122. with settings( warn_only=True ):
  123. cmd = ''
  124. for env_shell_file_path in env_shell_file_paths:
  125. for i, env_setting in enumerate( open( env_shell_file_path ) ):
  126. cmd += '%s\n' % env_setting
  127. cmd += action_dict[ 'command' ]
  128. return_code = handle_command( app, tool_dependency, install_dir, cmd )
  129. if return_code:
  130. return
  131. def log_results( command, fabric_AttributeString, file_path ):
  132. """
  133. Write attributes of fabric.operations._AttributeString (which is the output of executing command using fabric's local() method)
  134. to a specified log file.
  135. """
  136. if os.path.exists( file_path ):
  137. logfile = open( file_path, 'ab' )
  138. else:
  139. logfile = open( file_path, 'wb' )
  140. logfile.write( "\n#############################################\n" )
  141. logfile.write( '%s\nSTDOUT\n' % command )
  142. logfile.write( str( fabric_AttributeString.stdout ) )
  143. logfile.write( "\n#############################################\n" )
  144. logfile.write( "\n#############################################\n" )
  145. logfile.write( '%s\nSTDERR\n' % command )
  146. logfile.write( str( fabric_AttributeString.stderr ) )
  147. logfile.write( "\n#############################################\n" )
  148. logfile.close()
  149. @contextmanager
  150. def make_tmp_dir():
  151. work_dir = tempfile.mkdtemp()
  152. yield work_dir
  153. if os.path.exists( work_dir ):
  154. local( 'rm -rf %s' % work_dir )
  155. def set_galaxy_environment( galaxy_user, tool_dependency_dir, host='localhost', shell='/bin/bash -l -c' ):
  156. """General Galaxy environment configuration. This method is not currently used."""
  157. env.user = galaxy_user
  158. env.install_dir = tool_dependency_dir
  159. env.host_string = host
  160. env.shell = shell
  161. env.use_sudo = False
  162. env.safe_cmd = local
  163. return env