From ba91ecef9fc5afb6ff786b60e6dfa0680cc8ca2f Mon Sep 17 00:00:00 2001 From: Greg Von Kuster Date: Fri, 22 Jun 2012 10:21:09 -0400 Subject: [PATCH] Refinements for installing and managing tool dependencies for tools contained in installed tool shed repositories. --- lib/galaxy/model/__init__.py | 60 +- lib/galaxy/model/mapping.py | 3 +- ...0102_add_tool_dependency_status_columns.py | 63 +++ lib/galaxy/tool_shed/install_manager.py | 3 +- .../tool_dependencies/common_util.py | 4 - .../tool_dependencies/fabric_util.py | 74 +-- .../tool_dependencies/install_util.py | 93 +-- lib/galaxy/util/shed_util.py | 89 ++- lib/galaxy/web/controllers/admin_toolshed.py | 535 +++++++++++------- lib/galaxy/web/controllers/tool_runner.py | 5 +- .../community/controllers/repository.py | 2 +- .../browse_repository.mako | 8 +- .../browse_tool_dependency.mako | 7 +- .../admin/tool_shed_repository/common.mako | 130 ++++- .../confirm_tool_dependency_install.mako | 86 +++ .../deactivate_or_uninstall_repository.mako | 2 +- .../install_missing_tool_dependencies.mako | 109 ---- .../install_tool_dependencies.mako | 71 ++- .../manage_repository.mako | 35 +- .../manage_tool_dependencies.mako | 19 +- .../reselect_tool_panel_section.mako | 5 +- .../select_tool_panel_section.mako | 1 + .../tool_dependencies_grid.mako | 8 + .../tool_dependency_installation_status.mako | 13 + .../uninstall_tool_dependencies.mako | 52 ++ templates/tool_form.mako | 2 +- 26 files changed, 951 insertions(+), 528 deletions(-) create mode 100644 lib/galaxy/model/migrate/versions/0102_add_tool_dependency_status_columns.py create mode 100644 templates/admin/tool_shed_repository/confirm_tool_dependency_install.mako delete mode 100644 templates/admin/tool_shed_repository/install_missing_tool_dependencies.mako create mode 100644 templates/admin/tool_shed_repository/tool_dependencies_grid.mako create mode 100644 templates/admin/tool_shed_repository/tool_dependency_installation_status.mako create mode 100644 templates/admin/tool_shed_repository/uninstall_tool_dependencies.mako diff --git a/lib/galaxy/model/__init__.py b/lib/galaxy/model/__init__.py index aab06264809..e1de1cfc8b7 100644 --- a/lib/galaxy/model/__init__.py +++ b/lib/galaxy/model/__init__.py @@ -2647,6 +2647,12 @@ class APIKeys( object ): pass class ToolShedRepository( object ): + installation_status = Bunch( CLONED='cloned', + SETTING_TOOL_VERSIONS='setting tool versions', + INSTALLING_TOOL_DEPENDENCIES='installing tool dependencies', + INSTALLED='installed', + ERROR='error', + UNINSTALLED='uninstalled' ) def __init__( self, id=None, create_time=None, tool_shed=None, name=None, description=None, owner=None, installed_changeset_revision=None, changeset_revision=None, ctx_rev=None, metadata=None, includes_datatypes=False, update_available=False, deleted=False, uninstalled=False, dist_to_shed=False ): @@ -2696,47 +2702,59 @@ class ToolShedRepository( object ): """Return the repository's tool dependencies that are currently installed.""" installed_dependencies = [] for tool_dependency in self.tool_dependencies: - if not tool_dependency.uninstalled: + if tool_dependency.status == ToolDependency.installation_status.INSTALLED: installed_dependencies.append( tool_dependency ) return installed_dependencies @property def missing_tool_dependencies( self ): """Return the repository's tool dependencies that are not currently installed, and may not ever have been installed.""" missing_dependencies = [] - # Get the dependency information from the metadata for comparison against the installed tool dependencies. - tool_dependencies = self.metadata.get( 'tool_dependencies', None ) - if tool_dependencies: - for dependency_key, requirements_dict in tool_dependencies.items(): - name = requirements_dict[ 'name' ] - version = requirements_dict[ 'version' ] - type = requirements_dict[ 'type' ] - if self.tool_dependencies: - found = False - for tool_dependency in self.tool_dependencies: - if tool_dependency.name==name and tool_dependency.version==version and tool_dependency.type==type: - found = True - if tool_dependency.uninstalled: - missing_dependencies.append( ( tool_dependency.name, tool_dependency.version, tool_dependency.type ) ) - break - if not found: - missing_dependencies.append( ( name, version, type ) ) + for tool_dependency in self.tool_dependencies: + if tool_dependency.status in [ ToolDependency.installation_status.NEVER_INSTALLED, + ToolDependency.installation_status.ERROR, + ToolDependency.installation_status.UNINSTALLED ]: + missing_dependencies.append( tool_dependency ) return missing_dependencies @property + def tool_dependencies_being_installed( self ): + dependencies_being_installed = [] + for tool_dependency in self.tool_dependencies: + if tool_dependency.status == ToolDependency.installation_status.INSTALLING: + dependencies_being_installed.append( tool_dependency ) + return dependencies_being_installed + @property + def tool_dependencies_with_installation_errors( self ): + dependencies_with_installation_errors = [] + for tool_dependency in self.tool_dependencies: + if tool_dependency.status == ToolDependency.installation_status.ERROR: + dependencies_with_installation_errors.append( tool_dependency ) + return dependencies_with_installation_errors + @property def uninstalled_tool_dependencies( self ): """Return the repository's tool dependencies that have been uninstalled.""" uninstalled_tool_dependencies = [] for tool_dependency in self.tool_dependencies: - if tool_dependency.uninstalled: + if tool_dependency.status == ToolDependency.installation_status.UNINSTALLED: uninstalled_tool_dependencies.append( tool_dependency ) return uninstalled_tool_dependencies class ToolDependency( object ): - def __init__( self, tool_shed_repository_id=None, name=None, version=None, type=None, uninstalled=False ): + installation_status = Bunch( NEVER_INSTALLED='Never installed', + INSTALLING='Installing', + INSTALLED='Installed', + ERROR='Error', + UNINSTALLED='Uninstalled' ) + states = Bunch( INSTALLING = 'running', + OK = 'ok', + ERROR = 'error', + UNINSTALLED = 'deleted_new' ) + def __init__( self, tool_shed_repository_id=None, name=None, version=None, type=None, status=None, error_message=None ): self.tool_shed_repository_id = tool_shed_repository_id self.name = name self.version = version self.type = type - self.uninstalled = uninstalled + self.status = status + self.error_message = error_message def installation_directory( self, app ): return os.path.join( app.config.tool_dependency_dir, self.name, diff --git a/lib/galaxy/model/mapping.py b/lib/galaxy/model/mapping.py index f46afbe5f53..dafb7d21000 100644 --- a/lib/galaxy/model/mapping.py +++ b/lib/galaxy/model/mapping.py @@ -398,7 +398,8 @@ ToolDependency.table = Table( "tool_dependency", metadata, Column( "name", TrimmedString( 255 ) ), Column( "version", Text ), Column( "type", TrimmedString( 40 ) ), - Column( "uninstalled", Boolean, default=False ) ) + Column( "status", TrimmedString( 255 ), nullable=False ), + Column( "error_message", TEXT ) ) ToolVersion.table = Table( "tool_version", metadata, Column( "id", Integer, primary_key=True ), diff --git a/lib/galaxy/model/migrate/versions/0102_add_tool_dependency_status_columns.py b/lib/galaxy/model/migrate/versions/0102_add_tool_dependency_status_columns.py new file mode 100644 index 00000000000..41b787dc729 --- /dev/null +++ b/lib/galaxy/model/migrate/versions/0102_add_tool_dependency_status_columns.py @@ -0,0 +1,63 @@ +""" +Migration script to add status and error_message columns to the tool_dependency table and drop the uninstalled column from the tool_dependency table. +""" + +from sqlalchemy import * +from sqlalchemy.orm import * +from migrate import * +from migrate.changeset import * + +import datetime +now = datetime.datetime.utcnow +# Need our custom types, but don't import anything else from model +from galaxy.model.custom_types import * + +import sys, logging +log = logging.getLogger( __name__ ) +log.setLevel(logging.DEBUG) +handler = logging.StreamHandler( sys.stdout ) +format = "%(name)s %(levelname)s %(asctime)s %(message)s" +formatter = logging.Formatter( format ) +handler.setFormatter( formatter ) +log.addHandler( handler ) + +metadata = MetaData( migrate_engine ) +db_session = scoped_session( sessionmaker( bind=migrate_engine, autoflush=False, autocommit=True ) ) + +def upgrade(): + print __doc__ + metadata.reflect() + ToolDependency_table = Table( "tool_dependency", metadata, autoload=True ) + col = Column( "status", TrimmedString( 255 ), nullable=False ) + try: + col.create( ToolDependency_table ) + assert col is ToolDependency_table.c.status + except Exception, e: + print "Adding status column to the tool_dependency table failed: %s" % str( e ) + col = Column( "error_message", TEXT ) + try: + col.create( ToolDependency_table ) + assert col is ToolDependency_table.c.error_message + except Exception, e: + print "Adding error_message column to the tool_dependency table failed: %s" % str( e ) + try: + ToolDependency_table.c.uninstalled.drop() + except Exception, e: + print "Dropping uninstalled column from the tool_dependency table failed: %s" % str( e ) +def downgrade(): + metadata.reflect() + ToolDependency_table = Table( "tool_dependency", metadata, autoload=True ) + try: + ToolDependency_table.c.status.drop() + except Exception, e: + print "Dropping column status from the tool_dependency table failed: %s" % str( e ) + try: + ToolDependency_table.c.error_message.drop() + except Exception, e: + print "Dropping column error_message from the tool_dependency table failed: %s" % str( e ) + col = Column( "uninstalled", Boolean, default=False ) + try: + col.create( ToolDependency_table ) + assert col is ToolDependency_table.c.uninstalled + except Exception, e: + print "Adding uninstalled column to the tool_dependency table failed: %s" % str( e ) diff --git a/lib/galaxy/tool_shed/install_manager.py b/lib/galaxy/tool_shed/install_manager.py index 0ceafa73cd6..92a67ac33ff 100644 --- a/lib/galaxy/tool_shed/install_manager.py +++ b/lib/galaxy/tool_shed/install_manager.py @@ -7,7 +7,6 @@ from galaxy.tools import ToolSection from galaxy.util.json import from_json_string, to_json_string from galaxy.util.shed_util import * from galaxy.util.odict import odict -from galaxy.tool_shed.migrate.common import * REPOSITORY_OWNER = 'devteam' @@ -177,7 +176,7 @@ class InstallManager( object ): status, message = handle_tool_dependencies( app=self.app, tool_shed_repository=tool_shed_repository, tool_dependencies_config=tool_dependencies_config ) - if status != 'ok' and message: + if status != 'done' and message: print 'The following error occurred from the InstallManager while installing tool dependencies:' print message add_to_tool_panel( self.app, diff --git a/lib/galaxy/tool_shed/tool_dependencies/common_util.py b/lib/galaxy/tool_shed/tool_dependencies/common_util.py index 1597fb4ffa2..28da261b527 100644 --- a/lib/galaxy/tool_shed/tool_dependencies/common_util.py +++ b/lib/galaxy/tool_shed/tool_dependencies/common_util.py @@ -1,10 +1,6 @@ import os, shutil, tarfile, urllib2 from galaxy.datatypes.checkers import * -MISCELLANEOUS_ACTIONS = [ 'change_directory' ] -MOVE_ACTIONS = [ 'move_directory_files', 'move_file' ] -ALL_ACTIONS = MISCELLANEOUS_ACTIONS + MOVE_ACTIONS - def extract_tar( file_name, file_path ): if isgzip( file_name ) or isbz2( file_name ): # Open for reading with transparent compression. diff --git a/lib/galaxy/tool_shed/tool_dependencies/fabric_util.py b/lib/galaxy/tool_shed/tool_dependencies/fabric_util.py index 9d29e27f162..7b540e10388 100644 --- a/lib/galaxy/tool_shed/tool_dependencies/fabric_util.py +++ b/lib/galaxy/tool_shed/tool_dependencies/fabric_util.py @@ -13,6 +13,8 @@ pkg_resources.require( 'Fabric' ) from fabric.api import env, lcd, local, settings +INSTALLATION_LOG = 'INSTALLATION.log' + def check_fabric_version(): version = env.version if int( version.split( "." )[ 0 ] ) < 1: @@ -32,16 +34,19 @@ def make_tmp_dir(): yield work_dir if os.path.exists( work_dir ): local( 'rm -rf %s' % work_dir ) -def handle_post_build_processing( tool_dependency_dir, install_dir, env_dependency_path, package_name=None ): +def handle_post_build_processing( app, tool_dependency, install_dir, env_dependency_path, package_name=None ): + sa_session = app.model.context.current cmd = "echo 'PATH=%s:$PATH; export PATH' > %s/env.sh;chmod +x %s/env.sh" % ( env_dependency_path, install_dir, install_dir ) - message = '' output = local( cmd, capture=True ) - log_results( cmd, output, os.path.join( install_dir, 'env_sh.log' ) ) + log_results( cmd, output, os.path.join( install_dir, INSTALLATION_LOG ) ) if output.return_code: - message = '%s %s' % ( message, str( output.stderr ) ) - return message -def install_and_build_package( params_dict ): + tool_dependency.status = app.model.ToolDependency.installation_status.ERROR + tool_dependency.error_message = str( output.stderr ) + sa_session.add( tool_dependency ) + sa_session.flush() +def install_and_build_package( app, tool_dependency, params_dict ): """Install a Galaxy tool dependency package either via a url or a mercurial or git clone command.""" + sa_session = app.model.context.current install_dir = params_dict[ 'install_dir' ] download_url = params_dict.get( 'download_url', None ) clone_cmd = params_dict.get( 'clone_cmd', None ) @@ -59,43 +64,38 @@ def install_and_build_package( params_dict ): dir = work_dir elif clone_cmd: output = local( clone_cmd, capture=True ) - log_results( clone_cmd, output, os.path.join( install_dir, 'clone_repository.log' ) ) + log_results( clone_cmd, output, os.path.join( install_dir, INSTALLATION_LOG ) ) if output.return_code: - return '%s. ' % str( output.stderr ) + tool_dependency.status = app.model.ToolDependency.installation_status.ERROR + tool_dependency.error_message = str( output.stderr ) + sa_session.add( tool_dependency ) + sa_session.flush() + return dir = package_name if actions: with lcd( dir ): current_dir = os.path.abspath( os.path.join( work_dir, dir ) ) for action_tup in actions: action_key, action_dict = action_tup - if action_key.find( 'v^v^v' ) >= 0: - action_items = action_key.split( 'v^v^v' ) - action_name = action_items[ 0 ] - action = action_items[ 1 ] - elif action_key in common_util.ALL_ACTIONS: - action_name = action_key - else: - action_name = None - if action_name: - if action_name == 'change_directory': - current_dir = os.path.join( current_dir, action ) - lcd( current_dir ) - elif action_name == 'move_directory_files': - common_util.move_directory_files( current_dir=current_dir, - source_dir=os.path.join( action_dict[ 'source_directory' ] ), - destination_dir=os.path.join( action_dict[ 'destination_directory' ] ) ) - elif action_name == 'move_file': - common_util.move_file( current_dir=current_dir, - source=os.path.join( action_dict[ 'source' ] ), - destination_dir=os.path.join( action_dict[ 'destination' ] ) ) + if action_key == 'move_directory_files': + common_util.move_directory_files( current_dir=current_dir, + source_dir=os.path.join( action_dict[ 'source_directory' ] ), + destination_dir=os.path.join( action_dict[ 'destination_directory' ] ) ) + elif action_key == 'move_file': + common_util.move_file( current_dir=current_dir, + source=os.path.join( action_dict[ 'source' ] ), + destination_dir=os.path.join( action_dict[ 'destination' ] ) ) else: action = action_key with settings( warn_only=True ): output = local( action, capture=True ) - log_results( action, output, os.path.join( install_dir, 'actions.log' ) ) + log_results( action, output, os.path.join( install_dir, INSTALLATION_LOG ) ) if output.return_code: - return '%s. ' % str( output.stderr ) - return '' + tool_dependency.status = app.model.ToolDependency.installation_status.ERROR + tool_dependency.error_message = str( output.stderr ) + sa_session.add( tool_dependency ) + sa_session.flush() + return def log_results( command, fabric_AttributeString, file_path ): """ Write attributes of fabric.operations._AttributeString (which is the output of executing command using fabric's local() method) @@ -105,12 +105,12 @@ def log_results( command, fabric_AttributeString, file_path ): logfile = open( file_path, 'ab' ) else: logfile = open( file_path, 'wb' ) - logfile.write( "\n#############################################" ) - logfile.write( '\n%s\nSTDOUT\n' % command ) + logfile.write( "\n#############################################\n" ) + logfile.write( '%s\nSTDOUT\n' % command ) logfile.write( str( fabric_AttributeString.stdout ) ) - logfile.write( "#############################################\n" ) - logfile.write( "\n#############################################" ) - logfile.write( '\n%s\nSTDERR\n' % command ) + logfile.write( "\n#############################################\n" ) + logfile.write( "\n#############################################\n" ) + logfile.write( '%s\nSTDERR\n' % command ) logfile.write( str( fabric_AttributeString.stderr ) ) - logfile.write( "#############################################\n" ) + logfile.write( "\n#############################################\n" ) logfile.close() diff --git a/lib/galaxy/tool_shed/tool_dependencies/install_util.py b/lib/galaxy/tool_shed/tool_dependencies/install_util.py index e6c0c61fb59..d103171de59 100644 --- a/lib/galaxy/tool_shed/tool_dependencies/install_util.py +++ b/lib/galaxy/tool_shed/tool_dependencies/install_util.py @@ -11,19 +11,16 @@ pkg_resources.require( 'elementtree' ) from elementtree import ElementTree, ElementInclude from elementtree.ElementTree import Element, SubElement -def create_or_update_tool_dependency( app, tool_shed_repository, name, version, type ): +def create_or_update_tool_dependency( app, tool_shed_repository, name, version, type, status ): # Called from Galaxy (never the tool shed) when a new repository is being installed or when an uninstalled repository is being reinstalled. - # First see if an appropriate tool_dependency record exists for the received tool_shed_repository. sa_session = app.model.context.current + # First see if an appropriate tool_dependency record exists for the received tool_shed_repository. tool_dependency = get_tool_dependency_by_name_version_type_repository( app, tool_shed_repository, name, version, type ) if tool_dependency: - tool_dependency.uninstalled = False + tool_dependency.status = status else: # Create a new tool_dependency record for the tool_shed_repository. - tool_dependency = app.model.ToolDependency( tool_shed_repository_id=tool_shed_repository.id, - name=name, - version=version, - type=type ) + tool_dependency = app.model.ToolDependency( tool_shed_repository.id, name, version, type, status ) sa_session.add( tool_dependency ) sa_session.flush() return tool_dependency @@ -42,14 +39,15 @@ def get_tool_dependency_install_dir( app, repository, package_name, package_vers repository.owner, repository.name, repository.installed_changeset_revision ) ) -def install_package( app, elem, tool_shed_repository, name=None, version=None ): - # If name and version are not None, then a specific tool dependency is being installed. - message = '' +def install_package( app, elem, tool_shed_repository, tool_dependencies=None ): + # The value of tool_dependencies is a partial or full list of ToolDependency records associated with the tool_shed_repository. + sa_session = app.model.context.current + tool_dependency = None # The value of package_name should match the value of the "package" type in the tool config's tag set, but it's not required. package_name = elem.get( 'name', None ) package_version = elem.get( 'version', None ) if package_name and package_version: - if ( not name and not version ) or ( name and version and name==package_name and version==package_version ): + if tool_dependencies: install_dir = get_tool_dependency_install_dir( app, tool_shed_repository, package_name, package_version ) if not os.path.exists( install_dir ): for package_elem in elem: @@ -66,26 +64,22 @@ def install_package( app, elem, tool_shed_repository, name=None, version=None ): # Handle tool dependency installation using a fabric method included in the Galaxy framework. fabfile_path = None for method_elem in package_elem: - error_message = run_fabric_method( app, - method_elem, - fabfile_path, - app.config.tool_dependency_dir, - install_dir, - package_name=package_name ) - if error_message: - message += '%s' % error_message - else: - tool_dependency = create_or_update_tool_dependency( app, - tool_shed_repository, - name=package_name, - version=package_version, - type='package' ) + tool_dependency = create_or_update_tool_dependency( app, + tool_shed_repository, + name=package_name, + version=package_version, + type='package', + status=app.model.ToolDependency.installation_status.INSTALLING ) + run_fabric_method( app, tool_dependency, method_elem, fabfile_path, install_dir, package_name=package_name ) + sa_session.refresh( tool_dependency ) + if tool_dependency.status != app.model.ToolDependency.installation_status.ERROR: print package_name, 'version', package_version, 'installed in', install_dir else: print '\nSkipping installation of tool dependency', package_name, 'version', package_version, 'since it is installed in', install_dir, '\n' - return message -def run_fabric_method( app, elem, fabfile_path, tool_dependency_dir, install_dir, package_name=None, **kwd ): + return tool_dependency +def run_fabric_method( app, tool_dependency, elem, fabfile_path, install_dir, package_name=None, **kwd ): """Parse a tool_dependency.xml file's fabfile tag set to build the method parameters and execute the method.""" + sa_session = app.model.context.current if not os.path.exists( install_dir ): os.makedirs( install_dir ) # Default value for env_dependency_path. @@ -109,7 +103,7 @@ def run_fabric_method( app, elem, fabfile_path, tool_dependency_dir, install_dir action_key = action_elem.text.replace( '$INSTALL_DIR', install_dir ) if not action_key: continue - elif action_type in MOVE_ACTIONS: + elif action_type in [ 'move_directory_files', 'move_file' ]: # Examples: # # misc/some_file @@ -124,9 +118,6 @@ def run_fabric_method( app, elem, fabfile_path, tool_dependency_dir, install_dir move_elem_text = move_elem.text.replace( '$INSTALL_DIR', install_dir ) if move_elem_text: action_dict[ move_elem.tag ] = move_elem_text - elif action_elem.text: - # Example: bin - action_key = '%sv^v^v%s' % ( action_type, action_elem.text ) else: continue actions.append( ( action_key, action_dict ) ) @@ -141,24 +132,36 @@ def run_fabric_method( app, elem, fabfile_path, tool_dependency_dir, install_dir params_dict[ 'package_name' ] = package_name if fabfile_path: # TODO: Handle this using the fabric api. - # run_proprietary_fabric_method( app, elem, fabfile_path, tool_dependency_dir, install_dir, package_name=package_name ) + # run_proprietary_fabric_method( app, elem, fabfile_path, install_dir, package_name=package_name ) return 'Tool dependency installation using proprietary fabric scripts is not yet supported. ' else: # There is currently only 1 fabric method, install_and_build_package(). try: - message = install_and_build_package( params_dict ) - if message: - return message + install_and_build_package( app, tool_dependency, params_dict ) except Exception, e: - return '%s. ' % str( e ) - try: - message = handle_post_build_processing( tool_dependency_dir, install_dir, env_dependency_path, package_name=package_name ) - if message: - return message - except: - return '%s. ' % str( e ) - return '' -def run_proprietary_fabric_method( app, elem, fabfile_path, tool_dependency_dir, install_dir, package_name=None, **kwd ): + tool_dependency.status = app.model.ToolDependency.installation_status.ERROR + tool_dependency.error_message = str( e ) + sa_session.add( tool_dependency ) + sa_session.flush() + sa_session.refresh( tool_dependency ) + if tool_dependency.status != app.model.ToolDependency.installation_status.ERROR: + try: + handle_post_build_processing( app, + tool_dependency, + install_dir, + env_dependency_path, + package_name=package_name ) + except Exception, e: + tool_dependency.status = app.model.ToolDependency.installation_status.ERROR + tool_dependency.error_message = str( e ) + sa_session.add( tool_dependency ) + sa_session.flush() + sa_session.refresh( tool_dependency ) + if tool_dependency.status != app.model.ToolDependency.installation_status.ERROR: + tool_dependency.status = app.model.ToolDependency.installation_status.INSTALLED + sa_session.add( tool_dependency ) + sa_session.flush() +def run_proprietary_fabric_method( app, elem, fabfile_path, install_dir, package_name=None, **kwd ): """ TODO: Handle this using the fabric api. Parse a tool_dependency.xml file's fabfile tag set to build the method parameters and execute the method. @@ -193,7 +196,7 @@ def run_proprietary_fabric_method( app, elem, fabfile_path, tool_dependency_dir, return "Exception executing fabric script %s: %s. " % ( str( fabfile_path ), str( e ) ) if returncode: return message - message = handle_post_build_processing( tool_dependency_dir, install_dir, env_dependency_path, package_name=package_name ) + message = handle_post_build_processing( app, tool_dependency, install_dir, env_dependency_path, package_name=package_name ) if message: return message else: diff --git a/lib/galaxy/util/shed_util.py b/lib/galaxy/util/shed_util.py index f238cc0e353..1a3aa849193 100644 --- a/lib/galaxy/util/shed_util.py +++ b/lib/galaxy/util/shed_util.py @@ -6,7 +6,7 @@ from galaxy import util from galaxy.datatypes.checkers import * from galaxy.util.json import * from galaxy.tools.search import ToolBoxSearch -from galaxy.tool_shed.tool_dependencies.install_util import install_package +from galaxy.tool_shed.tool_dependencies.install_util import create_or_update_tool_dependency, install_package from galaxy.tool_shed.encoding_util import * from galaxy.model.orm import * @@ -318,8 +318,8 @@ def create_or_update_tool_shed_repository( app, name, description, installed_cha # to be in the Galaxy distribution, but have been moved to the main Galaxy tool shed. if current_changeset_revision is None: # The current_changeset_revision is not passed if a repository is being installed for the first time. If a previously installed repository - # was later uninstalled, this value should be received as the value of that change set to which the repository had been updated just prior to - # it being uninstalled. + # was later uninstalled, this value should be received as the value of that change set to which the repository had been updated just prior + # to it being uninstalled. current_changeset_revision = installed_changeset_revision sa_session = app.model.context.current tool_shed = get_tool_shed_from_clone_url( repository_clone_url ) @@ -353,6 +353,37 @@ def create_or_update_tool_shed_repository( app, name, description, installed_cha sa_session.add( tool_shed_repository ) sa_session.flush() return tool_shed_repository +def create_tool_dependency_objects( app, tool_shed_repository, current_changeset_revision ): + # Create or update a ToolDependency for each entry in tool_dependencies_config. This method is called when installing a new tool_shed_repository. + tool_dependency_objects = [] + work_dir = make_tmp_directory() + # Get the tool_dependencies.xml file from the repository. + tool_dependencies_config = get_config_from_repository( app, + 'tool_dependencies.xml', + tool_shed_repository, + current_changeset_revision, + work_dir ) + tree = ElementTree.parse( tool_dependencies_config ) + root = tree.getroot() + ElementInclude.include( root ) + fabric_version_checked = False + for elem in root: + if elem.tag == 'package': + package_name = elem.get( 'name', None ) + package_version = elem.get( 'version', None ) + if package_name and package_version: + tool_dependency = create_or_update_tool_dependency( app, + tool_shed_repository, + name=package_name, + version=package_version, + type='package', + status=app.model.ToolDependency.installation_status.NEVER_INSTALLED ) + tool_dependency_objects.append( tool_dependency ) + try: + shutil.rmtree( work_dir ) + except: + pass + return tool_dependency_objects def generate_clone_url( trans, repository ): """Generate the URL for cloning a repository.""" tool_shed_url = get_url_from_repository_tool_shed( trans.app, repository ) @@ -1163,7 +1194,7 @@ def handle_sample_tool_data_table_conf_file( app, filename, persist=False ): message = str( e ) error = True return error, message -def handle_tool_dependencies( app, tool_shed_repository, tool_dependencies_config, name=None, version=None, type='package' ): +def handle_tool_dependencies( app, tool_shed_repository, tool_dependencies_config, tool_dependencies=None ): """ Install and build tool dependencies defined in the tool_dependencies_config. This config's tag sets can currently refer to installation methods in Galaxy's tool_dependencies module. In the future, proprietary fabric scripts contained in the repository will be supported. @@ -1171,7 +1202,7 @@ def handle_tool_dependencies( app, tool_shed_repository, tool_dependencies_confi will be installed in: ~////// """ - status = 'ok' + status = 'done' message = '' # Parse the tool_dependencies.xml config. tree = ElementTree.parse( tool_dependencies_config ) @@ -1179,12 +1210,24 @@ def handle_tool_dependencies( app, tool_shed_repository, tool_dependencies_confi ElementInclude.include( root ) fabric_version_checked = False for elem in root: - if elem.tag == type: - error_message = install_package( app, elem, tool_shed_repository, name=name, version=version ) - if error_message: - message += ' %s' % error_message - if message: - status = 'error' + if elem.tag == 'package': + package_name = elem.get( 'name', None ) + package_version = elem.get( 'version', None ) + if package_name and package_version: + can_install = True + if tool_dependencies: + # Only install the package if it is not already installed. + can_install = False + for tool_dependency in tool_dependencies: + if tool_dependency.name==package_name and tool_dependency.version==package_version: + can_install = tool_dependency.status in [ app.model.ToolDependency.installation_status.NEVER_INSTALLED, + app.model.ToolDependency.installation_status.UNINSTALLED ] + break + if can_install: + tool_dependency = install_package( app, elem, tool_shed_repository, tool_dependencies=tool_dependencies ) + if tool_dependency and tool_dependency.status == app.model.ToolDependency.installation_status.ERROR: + message = tool_dependency.error_message + status = 'error' return status, message def handle_tool_versions( app, tool_version_dicts, tool_shed_repository ): """ @@ -1247,13 +1290,11 @@ def load_installed_display_applications( installed_repository_dict, deactivate=F # Load or deactivate proprietary datatype display applications app.datatypes_registry.load_display_applications( installed_repository_dict=installed_repository_dict, deactivate=deactivate ) def load_repository_contents( trans, repository_name, description, owner, installed_changeset_revision, current_changeset_revision, ctx_rev, - tool_path, repository_clone_url, relative_install_dir, tool_shed=None, tool_section=None, shed_tool_conf=None, - install_tool_dependencies=False ): + tool_path, repository_clone_url, relative_install_dir, tool_shed=None, tool_section=None, shed_tool_conf=None ): """ Generate the metadata for the installed tool shed repository, among other things. This method is called from Galaxy (never the tool shed) when an admin is installing a new repository or reinstalling an uninstalled repository. """ - message = '' metadata_dict = generate_metadata_using_disk_files( trans.app.toolbox, relative_install_dir, repository_clone_url ) # Add a new record to the tool_shed_repository table if one doesn't already exist. If one exists but is marked deleted, undelete it. This # must happen before the call to add_to_tool_panel() below because tools will not be properly loaded if the repository is marked deleted. @@ -1285,20 +1326,6 @@ def load_repository_contents( trans, repository_name, description, owner, instal repository_tools_tups, sample_files_copied = handle_missing_index_file( trans.app, tool_path, sample_files, repository_tools_tups ) # Copy remaining sample files included in the repository to the ~/tool-data directory of the local Galaxy instance. copy_sample_files( trans.app, sample_files, sample_files_copied=sample_files_copied ) - if install_tool_dependencies and 'tool_dependencies' in metadata_dict: - # Get the tool_dependencies.xml file from the repository. - tool_dependencies_config = get_config_from_repository( trans.app, - 'tool_dependencies.xml', - tool_shed_repository, - current_changeset_revision, - work_dir ) - # Install dependencies for repository tools. - status, message = handle_tool_dependencies( app=trans.app, - tool_shed_repository=tool_shed_repository, - tool_dependencies_config=tool_dependencies_config ) - if status != 'ok' and message: - print 'The following error occurred from load_repository_contents while installing tool dependencies:' - print message add_to_tool_panel( app=trans.app, repository_name=repository_name, repository_clone_url=repository_clone_url, @@ -1340,7 +1367,9 @@ def load_repository_contents( trans, repository_name, description, owner, instal shutil.rmtree( work_dir ) except: pass - return tool_shed_repository, metadata_dict, message + if 'tool_dependencies' in metadata_dict: + tool_dependencies = create_tool_dependency_objects( trans.app, tool_shed_repository, current_changeset_revision ) + return tool_shed_repository, metadata_dict def make_tmp_directory(): tmp_dir = os.getenv( 'TMPDIR', '' ) if tmp_dir: @@ -1505,7 +1534,7 @@ def remove_tool_dependency( trans, tool_dependency ): error_message = "Error removing tool dependency installation directory %s: %s" % ( str( dependency_install_dir ), str( e ) ) log.debug( error_message ) if removed: - tool_dependency.uninstalled = True + tool_dependency.status = trans.model.ToolDependency.installation_status.UNINSTALLED trans.sa_session.add( tool_dependency ) trans.sa_session.flush() return removed, error_message diff --git a/lib/galaxy/web/controllers/admin_toolshed.py b/lib/galaxy/web/controllers/admin_toolshed.py index 136aad8dda7..c466f70053c 100644 --- a/lib/galaxy/web/controllers/admin_toolshed.py +++ b/lib/galaxy/web/controllers/admin_toolshed.py @@ -77,9 +77,71 @@ class RepositoryListGrid( grids.Grid ): def build_initial_query( self, trans, **kwd ): return trans.sa_session.query( self.model_class ) +class ToolDependencyGrid( grids.Grid ): + class NameColumn( grids.TextColumn ): + def get_value( self, trans, grid, tool_dependency ): + return tool_dependency.name + class VersionColumn( grids.TextColumn ): + def get_value( self, trans, grid, tool_dependency ): + return tool_dependency.version + class TypeColumn( grids.TextColumn ): + def get_value( self, trans, grid, tool_dependency ): + return tool_dependency.type + class StatusColumn( grids.TextColumn ): + def get_value( self, trans, grid, tool_dependency ): + if tool_dependency.status in [ trans.model.ToolDependency.installation_status.INSTALLING ]: + return tool_dependency.status + else: + if tool_dependency.status in [ trans.model.ToolDependency.installation_status.NEVER_INSTALLED, + trans.model.ToolDependency.installation_status.UNINSTALLED ]: + bgcolor = trans.model.ToolDependency.states.UNINSTALLED + elif tool_dependency.status in [ trans.model.ToolDependency.installation_status.ERROR ]: + bgcolor = trans.model.ToolDependency.states.ERROR + elif tool_dependency.status in [ trans.model.ToolDependency.installation_status.INSTALLED ]: + bgcolor = trans.model.ToolDependency.states.OK + rval = '
' % ( bgcolor, trans.security.encode_id( tool_dependency.id ) ) + rval += '%s
' % tool_dependency.status + return rval + + webapp = "galaxy" + title = "Tool Dependencies" + template = "admin/tool_shed_repository/tool_dependencies_grid.mako" + model_class = model.ToolDependency + default_sort_key = "-create_time" + num_rows_per_page = 50 + preserve_state = True + use_paging = False + columns = [ + NameColumn( "Name", + filterable="advanced" ), + VersionColumn( "Version", + filterable="advanced" ), + TypeColumn( "Type", + filterable="advanced" ), + StatusColumn( "Installation Status", + filterable="advanced" ), + ] + operations = [ + grids.GridOperation( "Install", + allow_multiple=True, + condition=( lambda item: item.status in [ model.ToolDependency.installation_status.NEVER_INSTALLED, + model.ToolDependency.installation_status.UNINSTALLED ] ) ), + grids.GridOperation( "Uninstall", + allow_multiple=True, + allow_popup=False, + condition=( lambda item: item.status in [ model.ToolDependency.installation_status.INSTALLED, + model.ToolDependency.installation_status.ERROR ] ) ) + ] + def apply_query_filter( self, trans, query, **kwd ): + tool_dependency_id = kwd.get( 'tool_dependency_id', None ) + if not tool_dependency_id: + return query + return query.filter_by( tool_dependency_id=trans.security.decode_id( tool_dependency_id ) ) + class AdminToolshed( AdminGalaxy ): repository_list_grid = RepositoryListGrid() + tool_dependency_grid = ToolDependencyGrid() @web.expose @web.require_admin @@ -153,9 +215,8 @@ class AdminToolshed( AdminGalaxy ): message = util.restore_text( params.get( 'message', '' ) ) status = params.get( 'status', 'done' ) tool_dependency = get_tool_dependency( trans, kwd[ 'id' ] ) - repository = get_repository( trans, kwd[ 'repository_id' ] ) return trans.fill_template( '/admin/tool_shed_repository/browse_tool_dependency.mako', - repository=repository, + repository=tool_dependency.tool_shed_repository, tool_dependency=tool_dependency, message=message, status=status ) @@ -187,6 +248,35 @@ class AdminToolshed( AdminGalaxy ): return trans.response.send_redirect( url ) @web.expose @web.require_admin + def confirm_tool_dependency_install( self, trans, **kwd ): + """Display a page enabling the Galaxy administrator to choose to install tool dependencies for a tool shed repository they are installing.""" + # This method is called from the tool shed (never Galaxy) when a tool shed repository that includes a file named tool_dependencies.xml + # is being installed into a local Galaxy instance. + message = kwd.get( 'message', '' ) + status = kwd.get( 'status', 'done' ) + tool_shed_url = kwd[ 'tool_shed_url' ] + repo_info_dict = kwd[ 'repo_info_dict' ] + includes_tools = util.string_as_bool( kwd.get( 'includes_tools', False ) ) + # Decode the encoded repo_info_dict param value. + dict_with_tool_dependencies = tool_shed_decode( repo_info_dict ) + # The repo_info_dict includes tool dependencies which we need to display so the user knows what will be installed. + new_repo_info_dict = {} + for name, repo_info_tuple in dict_with_tool_dependencies.items(): + description, repository_clone_url, changeset_revision, ctx_rev, repository_owner, tool_dependencies = repo_info_tuple + # Create a new repo_info_dict by eliminating tool-dependencies from the repo_info_tuple. + new_repo_info_dict[ name ] = ( description, repository_clone_url, changeset_revision, ctx_rev ) + repo_info_dict = tool_shed_encode( new_repo_info_dict ) + install_tool_dependencies_check_box = CheckboxField( 'install_tool_dependencies', checked=True ) + return trans.fill_template( '/admin/tool_shed_repository/confirm_tool_dependency_install.mako', + tool_shed_url=tool_shed_url, + repo_info_dict=repo_info_dict, + dict_with_tool_dependencies=dict_with_tool_dependencies, + includes_tools=includes_tools, + install_tool_dependencies_check_box=install_tool_dependencies_check_box, + message=message, + status=status ) + @web.expose + @web.require_admin def deactivate_or_uninstall_repository( self, trans, **kwd ): params = util.Params( kwd ) message = util.restore_text( params.get( 'message', '' ) ) @@ -270,71 +360,33 @@ class AdminToolshed( AdminGalaxy ): return get_repository_file_contents( file_path ) @web.expose @web.require_admin - def install_missing_tool_dependencies( self, trans, **kwd ): - """ - Install dependencies for tools included in the repository that were not installed when the repository was installed or that are - being reinstalled after the repository was uninstalled. - """ - reinstalling = util.string_as_bool( kwd.get( 'reinstalling', False ) ) - message = kwd.get( 'message', '' ) - status = kwd.get( 'status', 'done' ) - repository = get_repository( trans, kwd[ 'id' ] ) - install_tool_dependencies = CheckboxField.is_checked( kwd.get( 'install_tool_dependencies', '' ) ) - if not reinstalling and install_tool_dependencies and kwd.get( 'install_missing_tool_dependencies_button', False ): - shed_tool_conf, tool_path, relative_install_dir = get_tool_panel_config_tool_path_install_dir( trans.app, repository ) - repo_files_dir = os.path.abspath( os.path.join( relative_install_dir, repository.name ) ) - # Get the tool_dependencies.xml file from the repository. - work_dir = make_tmp_directory() - tool_dependencies_config = get_config_from_repository( trans.app, - 'tool_dependencies.xml', - repository, - repository.changeset_revision, - work_dir, - install_dir=relative_install_dir ) - status, message = handle_tool_dependencies( app=trans.app, - tool_shed_repository=repository, - tool_dependencies_config=tool_dependencies_config ) - try: - shutil.rmtree( work_dir ) - except: - pass - return trans.fill_template( '/admin/tool_shed_repository/manage_repository.mako', - repository=repository, - description=repository.description, - repo_files_dir=repo_files_dir, - message=message, - status=status ) - if reinstalling and kwd.get( 'install_missing_tool_dependencies_button', False ): - # The user has been presented the option to install tool dependencies, so redirect to reinstall the repository, sending - # along the user's choice. - return trans.response.send_redirect( web.url_for( controller='admin_toolshed', - action='reinstall_repository', - **kwd ) ) - tool_dependencies = repository.metadata[ 'tool_dependencies' ] - install_tool_dependencies_check_box = CheckboxField( 'install_tool_dependencies', checked=True ) - if not reinstalling: - # Filter the tool_dependencies dictionary to eliminate successfully installed dependencies. - filtered_tool_dependencies = {} - for missing_dependency_tup in repository.missing_tool_dependencies: - name, version, type = missing_dependency_tup - dependency_key = '%s/%s' % ( name, version ) - install_dir = get_tool_dependency_install_dir( trans.app, repository, name, version ) - filtered_tool_dependencies[ dependency_key ] = dict( name=name, type=type, version=version ) - tool_dependencies = filtered_tool_dependencies - no_changes = kwd.get( 'no_changes', '' ) - no_changes_checked = CheckboxField.is_checked( no_changes ) - new_tool_panel_section = kwd.get( 'new_tool_panel_section', '' ) - tool_panel_section = kwd.get( 'tool_panel_section', '' ) - return trans.fill_template( '/admin/tool_shed_repository/install_missing_tool_dependencies.mako', - repository=repository, - reinstalling=reinstalling, - tool_dependencies=tool_dependencies, - no_changes_checked=no_changes_checked, - new_tool_panel_section=new_tool_panel_section, - tool_panel_section=tool_panel_section, - install_tool_dependencies_check_box=install_tool_dependencies_check_box, - message=message, - status=status ) + def initiate_tool_dependency_installation( self, trans, tool_dependencies ): + """Install specified dependencies for repository tools.""" + # Get the tool_shed_repository from one of the tool_dependencies. + tool_shed_repository = tool_dependencies[ 0 ].tool_shed_repository + work_dir = make_tmp_directory() + # Get the tool_dependencies.xml file from the repository. + tool_dependencies_config = get_config_from_repository( trans.app, + 'tool_dependencies.xml', + tool_shed_repository, + tool_shed_repository.changeset_revision, + work_dir ) + status, message = handle_tool_dependencies( app=trans.app, + tool_shed_repository=tool_shed_repository, + tool_dependencies_config=tool_dependencies_config, + tool_dependencies=tool_dependencies ) + try: + shutil.rmtree( work_dir ) + except: + pass + tool_dependency_ids = [ trans.security.encode_id( td.id ) for td in tool_dependencies ] + if not message: + message = "Installed tool dependencies: %s" % ','.join( td.name for td in tool_dependencies ) + return trans.response.send_redirect( web.url_for( controller='admin_toolshed', + action='manage_tool_dependencies', + tool_dependency_ids=tool_dependency_ids, + message=message, + status=status ) ) @web.expose @web.require_admin def install_repository( self, trans, **kwd ): @@ -413,23 +465,19 @@ class AdminToolshed( AdminGalaxy ): clone_repository( repository_clone_url, os.path.abspath( relative_install_dir ), ctx_rev ) owner = get_repository_owner( clean_repository_clone_url( repository_clone_url ) ) tool_shed = clean_tool_shed_url( tool_shed_url ) - tool_shed_repository, metadata_dict, error_message = load_repository_contents( trans, - repository_name=name, - description=description, - owner=owner, - installed_changeset_revision=changeset_revision, - current_changeset_revision=changeset_revision, - ctx_rev=ctx_rev, - tool_path=tool_path, - repository_clone_url=repository_clone_url, - relative_install_dir=relative_install_dir, - tool_shed=tool_shed, - tool_section=tool_section, - shed_tool_conf=shed_tool_conf, - install_tool_dependencies=install_tool_dependencies ) - if error_message: - message += error_message - status = 'error' + tool_shed_repository, metadata_dict, = load_repository_contents( trans, + repository_name=name, + description=description, + owner=owner, + installed_changeset_revision=changeset_revision, + current_changeset_revision=changeset_revision, + ctx_rev=ctx_rev, + tool_path=tool_path, + repository_clone_url=repository_clone_url, + relative_install_dir=relative_install_dir, + tool_shed=tool_shed, + tool_section=tool_section, + shed_tool_conf=shed_tool_conf ) if 'tools' in metadata_dict: # Get the tool_versions from the tool shed for each tool in the installed change set. url = '%srepository/get_tool_versions?name=%s&owner=%s&changeset_revision=%s&webapp=galaxy&no_reset=true' % \ @@ -449,26 +497,28 @@ class AdminToolshed( AdminGalaxy ): if installed_repository_names: installed_repository_names.sort() num_repositories_installed = len( installed_repository_names ) - if install_tool_dependencies: - dependency_str = ' along with tool dependencies ' - else: - dependency_str = '' if tool_section: - message += 'Installed %d %s%sand all tools were loaded into tool panel section %s:
Installed repositories: ' % \ + message += 'Installed %d %s and all tools were loaded into tool panel section %s:
Installed repositories: ' % \ ( num_repositories_installed, inflector.cond_plural( num_repositories_installed, 'repository' ), - dependency_str, tool_section.name ) else: - message += 'Installed %d %s%s and all tools were loaded into the tool panel outside of any sections.
Installed repositories: ' % \ + message += 'Installed %d %s and all tools were loaded into the tool panel outside of any sections.
Installed repositories: ' % \ ( num_repositories_installed, - inflector.cond_plural( num_repositories_installed, 'repository' ), - dependency_str ) + inflector.cond_plural( num_repositories_installed, 'repository' ) ) for i, repo_name in enumerate( installed_repository_names ): if i == len( installed_repository_names ) -1: message += '%s.
' % repo_name else: message += '%s, ' % repo_name + if install_tool_dependencies: + tool_dependency_ids = [ trans.security.encode_id( td.id ) for td in tool_shed_repository.missing_tool_dependencies ] + return trans.response.send_redirect( web.url_for( controller='admin_toolshed', + action='manage_tool_dependencies', + operation='install', + tool_dependency_ids=tool_dependency_ids, + status=status, + message=message ) ) return trans.response.send_redirect( web.url_for( controller='admin_toolshed', action='browse_repositories', message=message, @@ -520,61 +570,42 @@ class AdminToolshed( AdminGalaxy ): @web.expose @web.require_admin def install_tool_dependencies( self, trans, **kwd ): - """Install dependencies for tools included in the repository when the repository is being installed.""" - message = kwd.get( 'message', '' ) - status = kwd.get( 'status', 'done' ) - tool_shed_url = kwd[ 'tool_shed_url' ] - repo_info_dict = kwd[ 'repo_info_dict' ] - includes_tools = util.string_as_bool( kwd.get( 'includes_tools', False ) ) - # Decode the encoded repo_info_dict param value. - dict_with_tool_dependencies = tool_shed_decode( repo_info_dict ) - # The repo_info_dict includes tool dependencies which we need to display so the user knows what will be installed. - new_repo_info_dict = {} - for name, repo_info_tuple in dict_with_tool_dependencies.items(): - description, repository_clone_url, changeset_revision, ctx_rev, repository_owner, tool_dependencies = repo_info_tuple - # Create a new repo_info_dict by eliminating tool-dependencies from the repo_info_tuple. - new_repo_info_dict[ name ] = ( description, repository_clone_url, changeset_revision, ctx_rev ) - repo_info_dict = tool_shed_encode( new_repo_info_dict ) - install_tool_dependencies_check_box = CheckboxField( 'install_tool_dependencies', checked=True ) + params = util.Params( kwd ) + message = util.restore_text( params.get( 'message', '' ) ) + status = params.get( 'status', 'done' ) + tool_dependency_ids = util.listify( params.get( 'tool_dependency_ids', None ) ) + if not tool_dependency_ids: + tool_dependency_ids = util.listify( params.get( 'id', None ) ) + tool_dependencies = [] + for tool_dependency_id in tool_dependency_ids: + tool_dependency = get_tool_dependency( trans, tool_dependency_id ) + tool_dependencies.append( tool_dependency ) + if kwd.get( 'install_tool_dependencies_button', False ): + # Filter tool dependencies to only those that are installed. + tool_dependencies_for_installation = [] + for tool_dependency in tool_dependencies: + if tool_dependency.status in [ trans.model.ToolDependency.installation_status.UNINSTALLED, + trans.model.ToolDependency.installation_status.ERROR ]: + tool_dependencies_for_installation.append( tool_dependency ) + if tool_dependencies_for_installation: + # Redirect back to the ToolDependencyGrid before initiating installation. + tool_dependency_ids = [ trans.security.encode_id( td.id ) for td in tool_dependencies_for_installation ] + new_kwd = dict( action='manage_tool_dependencies', + operation='initiate_tool_dependency_installation', + tool_dependency_ids=tool_dependency_ids, + message=message, + status=status ) + return self.tool_dependency_grid( trans, **new_kwd ) + else: + message = 'All of the selected tool dependencies are already installed.' + status = 'error' + return trans.response.send_redirect( web.url_for( controller='admin_toolshed', + action='manage_tool_dependencies', + tool_dependency_ids=tool_dependency_ids, + status=status, + message=message ) ) return trans.fill_template( '/admin/tool_shed_repository/install_tool_dependencies.mako', - tool_shed_url=tool_shed_url, - repo_info_dict=repo_info_dict, - dict_with_tool_dependencies=dict_with_tool_dependencies, - includes_tools=includes_tools, - install_tool_dependencies_check_box=install_tool_dependencies_check_box, - message=message, - status=status ) - @web.expose - @web.require_admin - def install_tool_dependency( self, trans, name, version, type, repository_id, **kwd ): - """Install dependencies for tools included in the repository when the repository is being installed.""" - message = kwd.get( 'message', '' ) - status = kwd.get( 'status', 'done' ) - repository = get_repository( trans, repository_id ) - shed_tool_conf, tool_path, relative_install_dir = get_tool_panel_config_tool_path_install_dir( trans.app, repository ) - repo_files_dir = os.path.abspath( os.path.join( relative_install_dir, repository.name ) ) - # Get the tool_dependencies.xml file from the repository. - work_dir = make_tmp_directory() - tool_dependencies_config = get_config_from_repository( trans.app, - 'tool_dependencies.xml', - repository, - repository.changeset_revision, - work_dir, - install_dir=relative_install_dir ) - status, message = handle_tool_dependencies( app=trans.app, - tool_shed_repository=repository, - tool_dependencies_config=tool_dependencies_config, - name=name, - version=version, - type=type ) - try: - shutil.rmtree( work_dir ) - except: - pass - return trans.fill_template( '/admin/tool_shed_repository/manage_repository.mako', - repository=repository, - description=repository.description, - repo_files_dir=repo_files_dir, + tool_dependencies=tool_dependencies, message=message, status=status ) @web.expose @@ -614,12 +645,79 @@ class AdminToolshed( AdminGalaxy ): params = util.Params( kwd ) message = util.restore_text( params.get( 'message', '' ) ) status = params.get( 'status', 'done' ) - repository_id = kwd[ 'id' ] - repository = get_repository( trans, repository_id ) - return trans.fill_template( '/admin/tool_shed_repository/manage_tool_dependencies.mako', - repository=repository, - message=message, - status=status ) + tool_dependency_id = params.get( 'tool_dependency_id', None ) + tool_dependency_ids = util.listify( params.get( 'tool_dependency_ids', None ) ) + if not tool_dependency_ids: + tool_dependency_ids = util.listify( params.get( 'id', None ) ) + if tool_dependency_id and tool_dependency_id not in tool_dependency_ids: + tool_dependency_ids.append( tool_dependency_id ) + tool_dependencies = [] + # We need a tool_shed_repository, so get it from one of the tool_dependencies. + tool_dependency = get_tool_dependency( trans, tool_dependency_ids[ 0 ] ) + tool_shed_repository = tool_dependency.tool_shed_repository + self.tool_dependency_grid.title = "Tool shed repository '%s' tool dependencies" % tool_shed_repository.name + self.tool_dependency_grid.global_actions = \ + [ grids.GridAction( label='Browse repository', + url_args=dict( controller='admin_toolshed', + action='browse_repository', + id=trans.security.encode_id( tool_shed_repository.id ) ) ), + grids.GridAction( label='Manage repository', + url_args=dict( controller='admin_toolshed', + action='manage_repository', + id=trans.security.encode_id( tool_shed_repository.id ) ) ), + grids.GridAction( label='Get updates', + url_args=dict( controller='admin_toolshed', + action='check_for_updates', + id=trans.security.encode_id( tool_shed_repository.id ) ) ), + grids.GridAction( label='Set tool versions', + url_args=dict( controller='admin_toolshed', + action='set_tool_versions', + id=trans.security.encode_id( tool_shed_repository.id ) ) ), + grids.GridAction( label='Deactivate or uninstall repository', + url_args=dict( controller='admin_toolshed', + action='deactivate_or_uninstall_repository', + id=trans.security.encode_id( tool_shed_repository.id ) ) ) ] + if 'operation' in kwd: + operation = kwd[ 'operation' ].lower() + if not tool_dependency_ids: + message = 'Select at least 1 tool dependency to %s.' % operation + kwd[ 'message' ] = message + kwd[ 'status' ] = 'error' + del kwd[ 'operation' ] + return trans.response.send_redirect( web.url_for( controller='admin_toolshed', + action='manage_tool_dependencies', + **kwd ) ) + if operation == 'browse': + return trans.response.send_redirect( web.url_for( controller='admin_toolshed', + action='browse_tool_dependency', + **kwd ) ) + elif operation == 'uninstall': + tool_dependencies_for_uninstallation = [] + for tool_dependency_id in tool_dependency_ids: + tool_dependency = get_tool_dependency( trans, tool_dependency_id ) + if tool_dependency.status in [ trans.model.ToolDependency.installation_status.INSTALLED, + trans.model.ToolDependency.installation_status.ERROR ]: + tool_dependencies_for_uninstallation.append( tool_dependency ) + if tool_dependencies_for_uninstallation: + return trans.response.send_redirect( web.url_for( controller='admin_toolshed', + action='uninstall_tool_dependencies', + **kwd ) ) + else: + kwd[ 'message' ] = 'All selected tool dependencies are already uninstalled.' + kwd[ 'status' ] = 'error' + elif operation == "install": + tool_dependencies_for_installation = [] + for tool_dependency_id in tool_dependency_ids: + tool_dependency = get_tool_dependency( trans, tool_dependency_id ) + if tool_dependency.status in [ trans.model.ToolDependency.installation_status.NEVER_INSTALLED, + trans.model.ToolDependency.installation_status.UNINSTALLED ]: + tool_dependencies_for_installation.append( tool_dependency ) + if tool_dependencies_for_installation: + self.initiate_tool_dependency_installation( trans, tool_dependencies_for_installation ) + else: + kwd[ 'message' ] = 'All selected tool dependencies are already installed.' + kwd[ 'status' ] = 'error' + return self.tool_dependency_grid( trans, **kwd ) @web.json @web.require_admin def open_folder( self, trans, folder_path ): @@ -710,39 +808,52 @@ class AdminToolshed( AdminGalaxy ): tool_section = trans.app.toolbox.tool_panel[ section_key ] else: tool_section = None - tool_shed_repository, metadata_dict, error_message = load_repository_contents( trans, - repository_name=repository.name, - description=repository.description, - owner=repository.owner, - installed_changeset_revision=repository.installed_changeset_revision, - current_changeset_revision=current_changeset_revision, - ctx_rev=ctx_rev, - tool_path=tool_path, - repository_clone_url=repository_clone_url, - relative_install_dir=relative_install_dir, - tool_shed=repository.tool_shed, - tool_section=tool_section, - shed_tool_conf=shed_tool_conf, - install_tool_dependencies=install_tool_dependencies ) - if error_message: - # We'll only have an error_message if there was a problem installing tool dependencies. - message += error_message - status = 'error' + tool_shed_repository, metadata_dict, load_repository_contents( trans, + repository_name=repository.name, + description=repository.description, + owner=repository.owner, + installed_changeset_revision=repository.installed_changeset_revision, + current_changeset_revision=current_changeset_revision, + ctx_rev=ctx_rev, + tool_path=tool_path, + repository_clone_url=repository_clone_url, + relative_install_dir=relative_install_dir, + tool_shed=repository.tool_shed, + tool_section=tool_section, + shed_tool_conf=shed_tool_conf ) repository.uninstalled = False repository.deleted = False trans.sa_session.add( repository ) trans.sa_session.flush() + message += 'The %s repository has been reinstalled. ' % repository.name if install_tool_dependencies: - dependency_str = ' along with tool dependencies' - if error_message: - dependency_str += ', but with some errors installing the dependencies' - else: - dependency_str = ' without tool dependencies' - message += 'The %s repository has been reinstalled%s. ' % ( repository.name, dependency_str ) + message += 'The following tool dependencies are now being installed, please wait...' + tool_dependency_ids = [ trans.security.encode_id( td.id ) for td in tool_shed_repository.missing_tool_dependencies ] + return trans.response.send_redirect( web.url_for( controller='admin_toolshed', + action='manage_tool_dependencies', + operation='install', + tool_dependency_ids=tool_dependency_ids, + status=status, + message=message ) ) return trans.response.send_redirect( web.url_for( controller='admin_toolshed', action='browse_repositories', message=message, status=status ) ) + @web.json + def repository_installation_status_updates( self, trans, id=None, status=None ): + # Avoid caching + trans.response.headers[ 'Pragma' ] = 'no-cache' + trans.response.headers[ 'Expires' ] = '0' + # Create new HTML for any that have changed + rval = {} + if id is not None and status is not None: + repository = trans.sa_session.query( trans.model.ToolShedRepository ).get( trans.security.decode_id( id ) ) + if repository.status != status: + repository.status = status + rval[ id ] = { "status": repository.status, + "html_status": unicode( trans.fill_template( "admin/tool_shed_repository/repository_installation_status.mako", + repository=repository ), + 'utf-8' ) } @web.expose @web.require_admin def reselect_tool_panel_section( self, trans, **kwd ): @@ -811,22 +922,62 @@ class AdminToolshed( AdminGalaxy ): repo_files_dir=repo_files_dir, message=message, status=status ) + @web.json + def tool_dependency_status_updates( self, trans, ids=None, status_list=None ): + # Avoid caching + trans.response.headers[ 'Pragma' ] = 'no-cache' + trans.response.headers[ 'Expires' ] = '0' + # Create new HTML for any that have changed + rval = {} + if ids is not None and status_list is not None: + ids = ids.split( "," ) + status_list = status_list.split( "," ) + for id, status in zip( ids, status_list ): + tool_dependency = trans.sa_session.query( trans.model.ToolDependency ).get( trans.security.decode_id( id ) ) + if tool_dependency.status != status: + rval[ id ] = { "status": tool_dependency.status, + "html_status": unicode( trans.fill_template( "admin/tool_shed_repository/tool_dependency_installation_status.mako", + tool_dependency=tool_dependency ), + 'utf-8' ) } + return rval @web.expose @web.require_admin - def uninstall_tool_dependency( self, trans, **kwd ): + def uninstall_tool_dependencies( self, trans, **kwd ): params = util.Params( kwd ) message = util.restore_text( params.get( 'message', '' ) ) status = params.get( 'status', 'done' ) - repository = get_repository( trans, kwd[ 'repository_id' ] ) - tool_dependency = get_tool_dependency( trans, kwd[ 'id' ] ) - uninstalled, error_message = remove_tool_dependency( trans, tool_dependency ) - if uninstalled: - message = "The '%s' tool dependency has been uninstalled." % tool_dependency.name - else: - message = "Error attempting to uninstall the '%s' tool dependency: %s" % ( tool_dependency.name, error_message ) - status = 'error' - return trans.fill_template( '/admin/tool_shed_repository/manage_tool_dependencies.mako', - repository=repository, + tool_dependency_ids = util.listify( params.get( 'tool_dependency_ids', None ) ) + if not tool_dependency_ids: + tool_dependency_ids = util.listify( params.get( 'id', None ) ) + tool_dependencies = [] + for tool_dependency_id in tool_dependency_ids: + tool_dependency = get_tool_dependency( trans, tool_dependency_id ) + tool_dependencies.append( tool_dependency ) + if kwd.get( 'uninstall_tool_dependencies_button', False ): + errors = False + # Filter tool dependencies to only those that are installed. + tool_dependencies_for_uninstallation = [] + for tool_dependency in tool_dependencies: + if tool_dependency.status in [ trans.model.ToolDependency.installation_status.INSTALLED, + trans.model.ToolDependency.installation_status.ERROR ]: + tool_dependencies_for_uninstallation.append( tool_dependency ) + for tool_dependency in tool_dependencies_for_uninstallation: + uninstalled, error_message = remove_tool_dependency( trans, tool_dependency ) + if error_message: + errors = True + message = '%s %s' % ( message, error_message ) + if errors: + message = "Error attempting to uninstall tool dependencies: %s" % message + status = 'error' + else: + message = "These tool dependencies have been uninstalled: %s" % ','.join( td.name for td in tool_dependencies_for_uninstallation ) + return trans.response.send_redirect( web.url_for( controller='admin_toolshed', + action='manage_tool_dependencies', + tool_dependency_ids=tool_dependency_ids, + status=status, + message=message ) ) + return trans.fill_template( '/admin/tool_shed_repository/uninstall_tool_dependencies.mako', + tool_dependencies=tool_dependencies, message=message, status=status ) @web.expose @@ -864,11 +1015,14 @@ class AdminToolshed( AdminGalaxy ): repository.update_available = False trans.sa_session.add( repository ) trans.sa_session.flush() + # Create tool_dependency records if necessary. + if 'tool_dependencies' in metadata_dict: + tool_dependencies = create_tool_dependency_objects( trans.app, repository, repository.changeset_revision ) message = "The installed repository named '%s' has been updated to change set revision '%s'. " % ( name, latest_changeset_revision ) # See if any tool dependencies can be installed. shed_tool_conf, tool_path, relative_install_dir = get_tool_panel_config_tool_path_install_dir( trans.app, repository ) if repository.missing_tool_dependencies: - message += "Select Install tool dependencies from the repository's pop-up menu to install tool dependencies." + message += "Click the name of one of the missing tool dependencies listed below to install tool dependencies." else: message = "The directory containing the installed repository named '%s' cannot be found. " % name status = 'error' @@ -951,3 +1105,6 @@ def build_tool_panel_section_select_field( trans ): def get_repository( trans, id ): """Get a tool_shed_repository from the database via id""" return trans.sa_session.query( trans.model.ToolShedRepository ).get( trans.security.decode_id( id ) ) +def get_tool_dependency( trans, id ): + """Get a tool_dependency from the database via id""" + return trans.sa_session.query( trans.model.ToolDependency ).get( trans.security.decode_id( id ) ) diff --git a/lib/galaxy/web/controllers/tool_runner.py b/lib/galaxy/web/controllers/tool_runner.py index b43e7472e44..550aea5905b 100644 --- a/lib/galaxy/web/controllers/tool_runner.py +++ b/lib/galaxy/web/controllers/tool_runner.py @@ -128,18 +128,17 @@ class ToolRunner( BaseUIController ): else: tool_id_select_field = None tool = tools[ 0 ] - if tool.id == job.tool_id and tool.version == job.tool_version: + if ( tool.id == job.tool_id or tool.old_id == job.tool_id ) and tool.version == job.tool_version: tool_id_version_message = '' elif tool.id == job.tool_id: if job.tool_version == None: # For some reason jobs don't always keep track of the tool version. tool_id_version_message = '' else: + tool_id_version_message = 'This job was initially run with tool version "%s", which is not currently available. ' % job.tool_version if len( tools ) > 1: - tool_id_version_message = 'This job was initially run with tool version "%s", which is not currently available. ' % job.tool_version tool_id_version_message += 'You can rerun the job with the selected tool or choose another derivation of the tool.' else: - tool_id_version_message = 'This job was initially run with tool version "%s", which is not currently available. ' % job.tool_version tool_id_version_message += 'You can rerun the job with this tool version, which is a derivation of the original tool.' else: if len( tools ) > 1: diff --git a/lib/galaxy/webapps/community/controllers/repository.py b/lib/galaxy/webapps/community/controllers/repository.py index e0aa3474fec..679b35cc651 100644 --- a/lib/galaxy/webapps/community/controllers/repository.py +++ b/lib/galaxy/webapps/community/controllers/repository.py @@ -1229,7 +1229,7 @@ class RepositoryController( BaseUIController, ItemRatings ): encoded_repo_info_dict = encode( repo_info_dict ) if includes_tool_dependencies: # Redirect back to local Galaxy to present the option to install tool dependencies. - url = '%sadmin_toolshed/install_tool_dependencies?tool_shed_url=%s&repo_info_dict=%s&includes_tools=%s' % \ + url = '%sadmin_toolshed/confirm_tool_dependency_install?tool_shed_url=%s&repo_info_dict=%s&includes_tools=%s' % \ ( galaxy_url, url_for( '/', qualified=True ), encoded_repo_info_dict, str( includes_tools ) ) else: # Redirect back to local Galaxy to perform install. diff --git a/templates/admin/tool_shed_repository/browse_repository.mako b/templates/admin/tool_shed_repository/browse_repository.mako index ca977ecb9be..1b9065a5077 100644 --- a/templates/admin/tool_shed_repository/browse_repository.mako +++ b/templates/admin/tool_shed_repository/browse_repository.mako @@ -10,7 +10,7 @@ <%def name="javascripts()"> ${parent.javascripts()} ${h.js( "ui.core", "jquery.dynatree" )} - ${common_javascripts(repository.name, repository.repo_files_directory(trans.app))} + ${browse_files(repository.name, repository.repo_files_directory(trans.app))}

@@ -21,10 +21,8 @@ Get updates Deactivate or uninstall repository %if repository.tool_dependencies: - Manage tool dependencies - %endif - %if repository.missing_tool_dependencies: - Install missing tool dependencies + <% tool_dependency_ids = [ trans.security.encode_id( td.id ) for td in repository.tool_dependencies ] %> + Manage tool dependencies %endif diff --git a/templates/admin/tool_shed_repository/browse_tool_dependency.mako b/templates/admin/tool_shed_repository/browse_tool_dependency.mako index 96341da49b3..5e50832704b 100644 --- a/templates/admin/tool_shed_repository/browse_tool_dependency.mako +++ b/templates/admin/tool_shed_repository/browse_tool_dependency.mako @@ -10,9 +10,11 @@ <%def name="javascripts()"> ${parent.javascripts()} ${h.js( "ui.core", "jquery.dynatree" )} - ${common_javascripts(tool_dependency.name, tool_dependency.installation_directory( trans.app ))} + ${browse_files(tool_dependency.name, tool_dependency.installation_directory( trans.app ))} +<% tool_dependency_ids = [ trans.security.encode_id( td.id ) for td in repository.tool_dependencies ] %> +

diff --git a/templates/admin/tool_shed_repository/common.mako b/templates/admin/tool_shed_repository/common.mako index 14b99da26c2..7df116c48f1 100644 --- a/templates/admin/tool_shed_repository/common.mako +++ b/templates/admin/tool_shed_repository/common.mako @@ -1,4 +1,4 @@ -<%def name="common_javascripts(title_text, directory_path)"> +<%def name="browse_files(title_text, directory_path)"> + +<%def name="dependency_status_updater()"> + + + +<%def name="tool_dependency_installation_updater()"> + <% + can_update = False + if query.count(): + # Get the first tool dependency to get to the tool shed repository. + tool_dependency = query[0] + tool_shed_repository = tool_dependency.tool_shed_repository + can_update = tool_shed_repository.tool_dependencies_being_installed or tool_shed_repository.missing_tool_dependencies + %> + %if can_update: + + %endif + + +<%def name="repository_installation_status_updater()"> + + + +<%def name="repository_installation_updater()"> + <% + can_update = True + if tool_shed_repository: + can_update = tool_shed_repository.status not in [ trans.model.ToolShedRepository.installation_status.INSTALLED, + trans.model.ToolShedRepository.installation_status.ERROR, + trans.model.ToolShedRepository.installation_status.UNINSTALLED ] + %> + %if can_update: + + %endif + + diff --git a/templates/admin/tool_shed_repository/confirm_tool_dependency_install.mako b/templates/admin/tool_shed_repository/confirm_tool_dependency_install.mako new file mode 100644 index 00000000000..425e4af107e --- /dev/null +++ b/templates/admin/tool_shed_repository/confirm_tool_dependency_install.mako @@ -0,0 +1,86 @@ +<%inherit file="/base.mako"/> +<%namespace file="/message.mako" import="render_msg" /> + +<% import os %> + +%if message: + ${render_msg( message, status )} +%endif + +
+

+ The tool dependencies listed below can be automatically installed with the repository. Installing them provides significant + benefits and Galaxy includes various features to manage them. +

+

+ Each of these dependencies may require their own build requirements (e.g., CMake, g++, etc). Galaxy will not attempt to install + these build requirements, so if any are missing from your environment tool dependency installation may partially fail. The + repository and all of it's contents will be installed in any case. +

+

+ If tool dependency installation fails in any way, you can install the missing build requirements and have Galaxy attempt to install + the tool dependencies again using the Install tool dependencies pop-up menu option on the Manage repository page. +

+
+ +
+
+
+
+
+ + ${install_tool_dependencies_check_box.get_html()} +
+ Un-check to skip automatic installation of these tool dependencies. +
+
+
+
+ + + + + + + + + %for repository_name, repo_info_tuple in dict_with_tool_dependencies.items(): + <% + description, repository_clone_url, changeset_revision, ctx_rev, repository_owner, tool_dependencies = repo_info_tuple + %> + %for dependency_key, requirements_dict in tool_dependencies.items(): + <% + name = requirements_dict[ 'name' ] + version = requirements_dict[ 'version' ] + type = requirements_dict[ 'type' ] + install_dir = os.path.join( trans.app.config.tool_dependency_dir, + name, + version, + repository_owner, + repository_name, + changeset_revision ) + readme_text = requirements_dict.get( 'readme', None ) + %> + %if not os.path.exists( install_dir ): + + + + + + + %if readme_text: + + + %endif + %endif + %endfor + %endfor +
Tool dependencies
NameVersionTypeInstall directory
${name}${version}${type}${install_dir}
${name} ${version} requirements and installation information
${readme_text}
+
+
+
+ +
+
+
+
diff --git a/templates/admin/tool_shed_repository/deactivate_or_uninstall_repository.mako b/templates/admin/tool_shed_repository/deactivate_or_uninstall_repository.mako index 9a3d2edfe22..bc9fb75a6fd 100644 --- a/templates/admin/tool_shed_repository/deactivate_or_uninstall_repository.mako +++ b/templates/admin/tool_shed_repository/deactivate_or_uninstall_repository.mako @@ -86,7 +86,7 @@ * The repository's installed tool dependencies will be removed from disk.
- * Each associated tool dependency record's uninstalled column in the tool_dependency database table will be set to True. + * Each associated tool dependency record's status column in the tool_dependency database table will be set to 'Uninstalled'.
%endif %if repository.includes_datatypes: diff --git a/templates/admin/tool_shed_repository/install_missing_tool_dependencies.mako b/templates/admin/tool_shed_repository/install_missing_tool_dependencies.mako deleted file mode 100644 index 0506c0ec3fb..00000000000 --- a/templates/admin/tool_shed_repository/install_missing_tool_dependencies.mako +++ /dev/null @@ -1,109 +0,0 @@ -<%inherit file="/base.mako"/> -<%namespace file="/message.mako" import="render_msg" /> - -<% import os %> - -

- - -%if message: - ${render_msg( message, status )} -%endif - -
-

- Galaxy will attempt to install the missing tool dependencies listed below. Each of these dependencies may require their own build - requirements (e.g., CMake, g++, etc). Galaxy will not attempt to install these build requirements, so if any are missing from your - environment tool dependency installation may partially fail. If this happens, you can install the missing build requirements and - have Galaxy attempt to install the tool dependencies again. -

-
-
-
-

- Installation may take a while. Always wait until a message is displayed in your browser after clicking the Go button below. - If you get bored, watching your Galaxy server's paster log will help pass the time. -

-

- Information about the tool dependency installation process will be saved in various files named with a ".log" extension in the directory: - ${trans.app.config.tool_dependency_dir}/package name/package version/${repository.owner}/${repository.name}/${repository.changeset_revision} -

-
-
- -
-
-
-
-
- - ${install_tool_dependencies_check_box.get_html()} -
- Un-check to skip installation of these missing tool dependencies. -
- ## Fake the no_changes_check_box value. - %if no_changes_checked: - - %else: - - %endif -
-
-
- - - - - - - - - %for dependency_key, requirements_dict in tool_dependencies.items(): - <% - name = requirements_dict[ 'name' ] - version = requirements_dict[ 'version' ] - type = requirements_dict[ 'type' ] - install_dir = os.path.join( trans.app.config.tool_dependency_dir, - name, - version, - repository.owner, - repository.name, - repository.changeset_revision ) - readme_text = requirements_dict.get( 'readme', None ) - %> - %if not os.path.exists( install_dir ): - - - - - - - %if readme_text: - - - %endif - %endif - %endfor -
Missing tool dependencies
NameVersionTypeInstall directory
${name}${version}${type}${install_dir}
${name} ${version} requirements and installation information
${readme_text}
-
-
-
- -
-
-
-
diff --git a/templates/admin/tool_shed_repository/install_tool_dependencies.mako b/templates/admin/tool_shed_repository/install_tool_dependencies.mako index a7bd8aff93b..eb6e707bf4b 100644 --- a/templates/admin/tool_shed_repository/install_tool_dependencies.mako +++ b/templates/admin/tool_shed_repository/install_tool_dependencies.mako @@ -25,16 +25,7 @@
-
-
-
- - ${install_tool_dependencies_check_box.get_html()} -
- Un-check to skip automatic installation of these tool dependencies. -
-
-
+
@@ -44,42 +35,46 @@ - %for repository_name, repo_info_tuple in dict_with_tool_dependencies.items(): + <% tool_shed_repository = None %> + %for tool_dependency in tool_dependencies: + <% - description, repository_clone_url, changeset_revision, ctx_rev, repository_owner, tool_dependencies = repo_info_tuple + readme_text = None + if tool_shed_repository is None: + tool_shed_repository = tool_dependency.tool_shed_repository + metadata = tool_shed_repository.metadata + tool_dependencies_dict = metadata[ 'tool_dependencies' ] + for key, requirements_dict in tool_dependencies_dict.items(): + key_items = key.split( '/' ) + key_name = key_items[ 0 ] + key_version = key_items[ 1 ] + if key_name == tool_dependency.name and key_version == tool_dependency.version: + readme_text = requirements_dict.get( 'readme', None ) + install_dir = os.path.join( trans.app.config.tool_dependency_dir, + tool_dependency.name, + tool_dependency.version, + tool_shed_repository.owner, + tool_shed_repository.name, + tool_shed_repository.installed_changeset_revision ) %> - %for dependency_key, requirements_dict in tool_dependencies.items(): - <% - name = requirements_dict[ 'name' ] - version = requirements_dict[ 'version' ] - type = requirements_dict[ 'type' ] - install_dir = os.path.join( trans.app.config.tool_dependency_dir, - name, - version, - repository_owner, - repository_name, - changeset_revision ) - readme_text = requirements_dict.get( 'readme', None ) - %> - %if not os.path.exists( install_dir ): - - - - - - - %if readme_text: - - - %endif + %if not os.path.exists( install_dir ): + + + + + + + %if readme_text: + + %endif - %endfor + %endif %endfor
Tool dependencies
Type Install directory
${name}${version}${type}${install_dir}
${name} ${version} requirements and installation information
${readme_text}
${tool_dependency.name}${tool_dependency.version}${tool_dependency.type}${install_dir}
${tool_dependency.name} ${tool_dependency.version} requirements and installation information
${readme_text}
- +
diff --git a/templates/admin/tool_shed_repository/manage_repository.mako b/templates/admin/tool_shed_repository/manage_repository.mako index 701b1ac9da8..ac6aab67679 100644 --- a/templates/admin/tool_shed_repository/manage_repository.mako +++ b/templates/admin/tool_shed_repository/manage_repository.mako @@ -12,10 +12,8 @@ Set tool versions %endif %if repository.tool_dependencies: - Manage tool dependencies - %endif - %if repository.missing_tool_dependencies: - Install missing tool dependencies + <% tool_dependency_ids = [ trans.security.encode_id( td.id ) for td in repository.tool_dependencies ] %> + Manage tool dependencies %endif Deactivate or uninstall repository
@@ -91,21 +89,15 @@ version type - %for index, missing_dependency_tup in enumerate( missing_tool_dependencies ): - <% name, version, type = missing_dependency_tup %> + %for tool_dependency in missing_tool_dependencies: - - + + ${tool_dependency.name} + - ${version} - ${type} + ${tool_dependency.version} + ${tool_dependency.type} %endfor @@ -131,14 +123,9 @@ %for installed_tool_dependency in installed_tool_dependencies: - - + + ${installed_tool_dependency.name} + ${installed_tool_dependency.version} ${installed_tool_dependency.type} diff --git a/templates/admin/tool_shed_repository/manage_tool_dependencies.mako b/templates/admin/tool_shed_repository/manage_tool_dependencies.mako index 54ec39dfad2..5db835d4dbd 100644 --- a/templates/admin/tool_shed_repository/manage_tool_dependencies.mako +++ b/templates/admin/tool_shed_repository/manage_tool_dependencies.mako @@ -13,9 +13,6 @@ %if repository.includes_tools: Set tool versions %endif - %if repository.missing_tool_dependencies: - Install missing tool dependencies - %endif Deactivate or uninstall repository @@ -34,25 +31,25 @@ name = tool_dependency.name version = tool_dependency.version type = tool_dependency.type - uninstalled = tool_dependency.uninstalled + installed = tool_dependency.status == 'trans.model.ToolDependency.installation_status.INSTALLED install_dir = tool_dependency.installation_directory( trans.app ) %> @@ -64,7 +61,7 @@ Install directory - %if uninstalled: + %if not installed: This dependency is not currently installed %else: @@ -73,7 +70,7 @@ %endif - Uninstalled${uninstalled} + Installed${not installed} %endfor
diff --git a/templates/admin/tool_shed_repository/reselect_tool_panel_section.mako b/templates/admin/tool_shed_repository/reselect_tool_panel_section.mako index 8ffa3e02dd4..5a807612e6a 100644 --- a/templates/admin/tool_shed_repository/reselect_tool_panel_section.mako +++ b/templates/admin/tool_shed_repository/reselect_tool_panel_section.mako @@ -8,8 +8,9 @@
Choose the tool panel section to contain the installed tools (optional)
- %if repository.includes_tool_dependencies: -
+ %if repository.tool_dependencies: + <% tool_dependency_ids = [ trans.security.encode_id( td.id ) for td in repository.tool_dependencies ] %> + %else: %endif diff --git a/templates/admin/tool_shed_repository/select_tool_panel_section.mako b/templates/admin/tool_shed_repository/select_tool_panel_section.mako index e06cd51510c..66ee04dbf1e 100644 --- a/templates/admin/tool_shed_repository/select_tool_panel_section.mako +++ b/templates/admin/tool_shed_repository/select_tool_panel_section.mako @@ -78,6 +78,7 @@
Repository README file (may contain important installation or license information)
+
${readme_text}
diff --git a/templates/admin/tool_shed_repository/tool_dependencies_grid.mako b/templates/admin/tool_shed_repository/tool_dependencies_grid.mako new file mode 100644 index 00000000000..7dfdeffccc1 --- /dev/null +++ b/templates/admin/tool_shed_repository/tool_dependencies_grid.mako @@ -0,0 +1,8 @@ +<%inherit file="/grid_base.mako"/> +<%namespace file="/admin/tool_shed_repository/common.mako" import="*" /> + +<%def name="javascripts()"> + ${parent.javascripts()} + ${dependency_status_updater()} + ${tool_dependency_installation_updater()} + diff --git a/templates/admin/tool_shed_repository/tool_dependency_installation_status.mako b/templates/admin/tool_shed_repository/tool_dependency_installation_status.mako new file mode 100644 index 00000000000..fa6dfef7e26 --- /dev/null +++ b/templates/admin/tool_shed_repository/tool_dependency_installation_status.mako @@ -0,0 +1,13 @@ +<%def name="render_tool_dependency_status( tool_dependency )"> + <% + if tool_dependency.status == trans.model.ToolDependency.installation_status.INSTALLING: + bgcolor = trans.model.ToolDependency.states.INSTALLING + rval = '
' % ( bgcolor, trans.security.encode_id( tool_dependency.id ) ) + rval += '%s
' % tool_dependency.status + else: + rval = tool_dependency.status + %> + ${rval} + + +${render_tool_dependency_status( tool_dependency )} diff --git a/templates/admin/tool_shed_repository/uninstall_tool_dependencies.mako b/templates/admin/tool_shed_repository/uninstall_tool_dependencies.mako new file mode 100644 index 00000000000..faad244b998 --- /dev/null +++ b/templates/admin/tool_shed_repository/uninstall_tool_dependencies.mako @@ -0,0 +1,52 @@ +<%inherit file="/base.mako"/> +<%namespace file="/message.mako" import="render_msg" /> + +<% import os %> + +%if message: + ${render_msg( message, status )} +%endif + +
+
Uninstall tool dependencies
+
+ +
+ + + + + + + + %for tool_dependency in tool_dependencies: + + <% + install_dir = os.path.join( trans.app.config.tool_dependency_dir, + tool_dependency.name, + tool_dependency.version, + tool_dependency.tool_shed_repository.owner, + tool_dependency.tool_shed_repository.name, + tool_dependency.tool_shed_repository.installed_changeset_revision ) + %> + %if os.path.exists( install_dir ): + + + + + + + %endif + %endfor +
NameVersionTypeInstall directory
${tool_dependency.name}${tool_dependency.version}${tool_dependency.type}${install_dir}
+
+
+
+ +
+ Click to uninstall the tool dependencies listed above. +
+
+ +
+
diff --git a/templates/tool_form.mako b/templates/tool_form.mako index 72ea74b5b1d..69e8c665959 100644 --- a/templates/tool_form.mako +++ b/templates/tool_form.mako @@ -283,7 +283,7 @@ %> %if tool_id_version_message: - ${render_msg( tool_id_version_message, 'error' )} + ${render_msg( tool_id_version_message, 'warning' )} %endif