1 new commit in galaxy-central: https://bitbucket.org/galaxy/galaxy-central/changeset/db2bf8004964/ changeset: db2bf8004964 user: greg date: 2012-06-22 16:21:09 summary: Refinements for installing and managing tool dependencies for tools contained in installed tool shed repositories. affected #: 26 files diff -r a0a4f15fe0958c5ff2658c1695c63023b9cf6d39 -r db2bf800496478a5ea041480c3c514c2620e28ae lib/galaxy/model/__init__.py --- a/lib/galaxy/model/__init__.py +++ b/lib/galaxy/model/__init__.py @@ -2647,6 +2647,12 @@ 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 @@ """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 -r a0a4f15fe0958c5ff2658c1695c63023b9cf6d39 -r db2bf800496478a5ea041480c3c514c2620e28ae lib/galaxy/model/mapping.py --- a/lib/galaxy/model/mapping.py +++ b/lib/galaxy/model/mapping.py @@ -398,7 +398,8 @@ 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 -r a0a4f15fe0958c5ff2658c1695c63023b9cf6d39 -r db2bf800496478a5ea041480c3c514c2620e28ae lib/galaxy/model/migrate/versions/0102_add_tool_dependency_status_columns.py --- /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 -r a0a4f15fe0958c5ff2658c1695c63023b9cf6d39 -r db2bf800496478a5ea041480c3c514c2620e28ae lib/galaxy/tool_shed/install_manager.py --- a/lib/galaxy/tool_shed/install_manager.py +++ b/lib/galaxy/tool_shed/install_manager.py @@ -7,7 +7,6 @@ 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 @@ 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 -r a0a4f15fe0958c5ff2658c1695c63023b9cf6d39 -r db2bf800496478a5ea041480c3c514c2620e28ae lib/galaxy/tool_shed/tool_dependencies/common_util.py --- a/lib/galaxy/tool_shed/tool_dependencies/common_util.py +++ b/lib/galaxy/tool_shed/tool_dependencies/common_util.py @@ -1,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 -r a0a4f15fe0958c5ff2658c1695c63023b9cf6d39 -r db2bf800496478a5ea041480c3c514c2620e28ae lib/galaxy/tool_shed/tool_dependencies/fabric_util.py --- a/lib/galaxy/tool_shed/tool_dependencies/fabric_util.py +++ b/lib/galaxy/tool_shed/tool_dependencies/fabric_util.py @@ -13,6 +13,8 @@ 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 @@ 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 @@ 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 @@ 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 -r a0a4f15fe0958c5ff2658c1695c63023b9cf6d39 -r db2bf800496478a5ea041480c3c514c2620e28ae lib/galaxy/tool_shed/tool_dependencies/install_util.py --- a/lib/galaxy/tool_shed/tool_dependencies/install_util.py +++ b/lib/galaxy/tool_shed/tool_dependencies/install_util.py @@ -11,19 +11,16 @@ 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. + sa_session = app.model.context.current # First see if an appropriate tool_dependency record exists for the received tool_shed_repository. - sa_session = app.model.context.current 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 @@ 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 <requirements> 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 @@ # 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 <method> 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 @@ 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: # <action type="move_file"> # <source>misc/some_file</source> @@ -124,9 +118,6 @@ 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: <action type="change_directory">bin</action> - action_key = '%sv^v^v%s' % ( action_type, action_elem.text ) else: continue actions.append( ( action_key, action_dict ) ) @@ -141,24 +132,36 @@ 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 <method> tag set to build the method parameters and execute the method. @@ -193,7 +196,7 @@ 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 -r a0a4f15fe0958c5ff2658c1695c63023b9cf6d39 -r db2bf800496478a5ea041480c3c514c2620e28ae lib/galaxy/util/shed_util.py --- a/lib/galaxy/util/shed_util.py +++ b/lib/galaxy/util/shed_util.py @@ -6,7 +6,7 @@ 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 @@ # 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 @@ 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 @@ 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 @@ will be installed in: ~/<app.config.tool_dependency_dir>/<package_name>/<package_version>/<repo_owner>/<repo_name>/<repo_installed_changeset_revision> """ - status = 'ok' + status = 'done' message = '' # Parse the tool_dependencies.xml config. tree = ElementTree.parse( tool_dependencies_config ) @@ -1179,12 +1210,24 @@ 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 @@ # 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 @@ 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 @@ 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 @@ 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 -r a0a4f15fe0958c5ff2658c1695c63023b9cf6d39 -r db2bf800496478a5ea041480c3c514c2620e28ae lib/galaxy/web/controllers/admin_toolshed.py --- a/lib/galaxy/web/controllers/admin_toolshed.py +++ b/lib/galaxy/web/controllers/admin_toolshed.py @@ -77,9 +77,71 @@ 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 = '<div class="count-box state-color-%s" id="ToolDependencyStatus-%s">' % ( bgcolor, trans.security.encode_id( tool_dependency.id ) ) + rval += '%s</div>' % 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 <b>%s</b>:<br/>Installed repositories: ' % \ + message += 'Installed %d %s and all tools were loaded into tool panel section <b>%s</b>:<br/>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.<br/>Installed repositories: ' % \ + message += 'Installed %d %s and all tools were loaded into the tool panel outside of any sections.<br/>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.<br/>' % 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 @@ @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 @@ 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 @@ 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 <b>%s</b> 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 <b>%s</b> 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 @@ 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 @@ 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 <b>Install tool dependencies</b> 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 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 -r a0a4f15fe0958c5ff2658c1695c63023b9cf6d39 -r db2bf800496478a5ea041480c3c514c2620e28ae lib/galaxy/web/controllers/tool_runner.py --- a/lib/galaxy/web/controllers/tool_runner.py +++ b/lib/galaxy/web/controllers/tool_runner.py @@ -128,18 +128,17 @@ 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 -r a0a4f15fe0958c5ff2658c1695c63023b9cf6d39 -r db2bf800496478a5ea041480c3c514c2620e28ae lib/galaxy/webapps/community/controllers/repository.py --- a/lib/galaxy/webapps/community/controllers/repository.py +++ b/lib/galaxy/webapps/community/controllers/repository.py @@ -1229,7 +1229,7 @@ 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 -r a0a4f15fe0958c5ff2658c1695c63023b9cf6d39 -r db2bf800496478a5ea041480c3c514c2620e28ae templates/admin/tool_shed_repository/browse_repository.mako --- 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))} </%def><br/><br/> @@ -21,10 +21,8 @@ <a class="action-button" href="${h.url_for( controller='admin_toolshed', action='check_for_updates', id=trans.security.encode_id( repository.id ) )}">Get updates</a><a class="action-button" href="${h.url_for( controller='admin_toolshed', action='deactivate_or_uninstall_repository', id=trans.security.encode_id( repository.id ) )}">Deactivate or uninstall repository</a> %if repository.tool_dependencies: - <a class="action-button" href="${h.url_for( controller='admin_toolshed', action='manage_tool_dependencies', id=trans.security.encode_id( repository.id ) )}">Manage tool dependencies</a> - %endif - %if repository.missing_tool_dependencies: - <a class="action-button" href="${h.url_for( controller='admin_toolshed', action='install_missing_tool_dependencies', id=trans.security.encode_id( repository.id ) )}">Install missing tool dependencies</a> + <% tool_dependency_ids = [ trans.security.encode_id( td.id ) for td in repository.tool_dependencies ] %> + <a class="action-button" href="${h.url_for( controller='admin_toolshed', action='manage_tool_dependencies', tool_dependency_ids=tool_dependency_ids )}">Manage tool dependencies</a> %endif </div></ul> diff -r a0a4f15fe0958c5ff2658c1695c63023b9cf6d39 -r db2bf800496478a5ea041480c3c514c2620e28ae templates/admin/tool_shed_repository/browse_tool_dependency.mako --- a/templates/admin/tool_shed_repository/browse_tool_dependency.mako +++ b/templates/admin/tool_shed_repository/browse_tool_dependency.mako @@ -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 ))} </%def> +<% tool_dependency_ids = [ trans.security.encode_id( td.id ) for td in repository.tool_dependencies ] %> + <br/><br/><ul class="manage-table-actions"><li><a class="action-button" id="tool_dependency-${tool_dependency.id}-popup" class="menubutton">Repository Actions</a></li> @@ -21,8 +23,7 @@ <a class="action-button" href="${h.url_for( controller='admin_toolshed', action='manage_repository', id=trans.security.encode_id( repository.id ) )}">Manage repository</a><a class="action-button" href="${h.url_for( controller='admin_toolshed', action='check_for_updates', id=trans.security.encode_id( repository.id ) )}">Get updates</a><a class="action-button" href="${h.url_for( controller='admin_toolshed', action='deactivate_or_uninstall_repository', id=trans.security.encode_id( repository.id ) )}">Deactivate or uninstall repository</a> - <a class="action-button" href="${h.url_for( controller='admin_toolshed', action='manage_tool_dependencies', id=trans.security.encode_id( repository.id ) )}">Manage tool dependencies</a> - <a class="action-button" href="${h.url_for( controller='admin_toolshed', action='uninstall_tool_dependency', id=trans.security.encode_id( tool_dependency.id ), repository_id=trans.security.encode_id( repository.id ) )}">Uninstall this tool dependency</a> + <a class="action-button" href="${h.url_for( controller='admin_toolshed', action='manage_tool_dependencies', tool_dependency_ids=tool_dependency_ids )}">Manage tool dependencies</a></div></ul> diff -r a0a4f15fe0958c5ff2658c1695c63023b9cf6d39 -r db2bf800496478a5ea041480c3c514c2620e28ae templates/admin/tool_shed_repository/common.mako --- 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)"><script type="text/javascript"> $(function(){ $("#tree").ajaxComplete(function(event, XMLHttpRequest, ajaxOptions) { @@ -66,3 +66,131 @@ }); </script></%def> + +<%def name="dependency_status_updater()"> + <script type="text/javascript"> + + // Tool dependency status updater - used to update the installation status on the Tool Dependencies grid. + // Looks for changes in tool dependency installation status using an async request. Keeps calling itself + // (via setTimeout) until dependency installation status is neither 'Installing' nor 'Building'. + var tool_dependency_status_updater = function ( dependency_status_list ) { + // See if there are any items left to track + var empty = true; + for ( i in dependency_status_list ) { + empty = false; + break; + } + if ( ! empty ) { + setTimeout( function() { tool_dependency_status_updater_callback( dependency_status_list ) }, 3000 ); + } + }; + var tool_dependency_status_updater_callback = function ( dependency_status_list ) { + var ids = [] + var status_list = [] + $.each( dependency_status_list, function ( id, dependency_status ) { + ids.push( id ); + status_list.push( dependency_status ); + }); + // Make ajax call + $.ajax( { + type: "POST", + url: "${h.url_for( controller='admin_toolshed', action='tool_dependency_status_updates' )}", + dataType: "json", + data: { ids: ids.join( "," ), status_list: status_list.join( "," ) }, + success : function ( data ) { + $.each( data, function( id, val ) { + // Replace HTML + var cell1 = $("#ToolDependencyStatus-" + id); + cell1.html( val.html_status ); + dependency_status_list[ id ] = val.status; + }); + tool_dependency_status_updater( dependency_status_list ); + }, + error: function() { + tool_dependency_status_updater( dependency_status_list ); + } + }); + }; + </script> +</%def> + +<%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: + <script type="text/javascript"> + // Tool dependency installation status updater + tool_dependency_status_updater( {${ ",".join( [ '"%s" : "%s"' % ( trans.security.encode_id( td.id ), td.status ) for td in query ] ) }}); + </script> + %endif +</%def> + +<%def name="repository_installation_status_updater()"> + <script type="text/javascript"> + + // Tool shed repository status updater - used to update the installation status on the repository_installation.mako template. + // Looks for changes in repository installation status using an async request. Keeps calling itself (via setTimeout) until + // repository installation status is neither 'cloning', 'cloned' nor 'installing tool dependencies'. + var tool_shed_repository_status_updater = function ( repository_status_list ) { + // See if there are any items left to track + var empty = true; + for ( i in repository_status_list ) { + empty = false; + break; + } + if ( ! empty ) { + setTimeout( function() { tool_shed_repository_status_updater_callback( repository_status_list ) }, 3000 ); + } + }; + var tool_shed_repository_status_updater_callback = function ( repository_status_list ) { + var ids = [] + var status_list = [] + $.each( repository_status_list, function ( id, repository_status ) { + ids.push( id ); + status_list.push( repository_status ); + }); + // Make ajax call + $.ajax( { + type: "POST", + url: "${h.url_for( controller='admin_toolshed', action='repository_installation_status_updates' )}", + dataType: "json", + data: { id: ids[0], status_list: status_list.join( "," ) }, + success : function ( data ) { + $.each( data, function( id, val ) { + // Replace HTML + var cell1 = $("#RepositoryStatus-" + id); + cell1.html( val.html_status ); + repository_status_list[ id ] = val.status; + }); + tool_shed_repository_status_updater( repository_status_list ); + }, + error: function() { + tool_shed_repository_status_updater( repository_status_list ); + } + }); + }; + </script> +</%def> + +<%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: + <script type="text/javascript"> + // Tool shed repository installation status updater + repository_installation_status_updater( {${ ",".join( [ '"%s" : "%s"' % ( trans.security.encode_id( repository.id ), repository.status ) for repository in query ] ) }}); + </script> + %endif +</%def> + diff -r a0a4f15fe0958c5ff2658c1695c63023b9cf6d39 -r db2bf800496478a5ea041480c3c514c2620e28ae templates/admin/tool_shed_repository/confirm_tool_dependency_install.mako --- /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 + +<div class="warningmessage"> + <p> + 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. + </p> + <p> + 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. + </p> + <p> + 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 <b>Install tool dependencies</b> pop-up menu option on the <b>Manage repository</b> page. + </p> +</div> + +<div class="toolForm"> + <div class="toolFormBody"> + <form name="confirm_tool_dependency_install" id="confirm_tool_dependency_install" action="${h.url_for( controller='admin_toolshed', action='install_repository', tool_shed_url=tool_shed_url, repo_info_dict=repo_info_dict, includes_tools=includes_tools )}" method="post" > + <div style="clear: both"></div> + <div class="form-row"> + <label>Install tool dependencies?</label> + ${install_tool_dependencies_check_box.get_html()} + <div class="toolParamHelp" style="clear: both;"> + Un-check to skip automatic installation of these tool dependencies. + </div> + </div> + <div style="clear: both"></div> + <div class="form-row"> + <table class="grid"> + <tr><td colspan="4" bgcolor="#D8D8D8"><b>Tool dependencies</b></td></tr> + <tr> + <th>Name</th> + <th>Version</th> + <th>Type</th> + <th>Install directory</th> + </tr> + %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 ): + <tr> + <td>${name}</td> + <td>${version}</td> + <td>${type}</td> + <td>${install_dir}</td> + </tr> + %if readme_text: + <tr><td colspan="4" bgcolor="#FFFFCC">${name} ${version} requirements and installation information</td></tr> + <tr><td colspan="4"><pre>${readme_text}</pre></td></tr> + %endif + %endif + %endfor + %endfor + </table> + <div style="clear: both"></div> + </div> + <div class="form-row"> + <input type="submit" name="confirm_tool_dependency_install_button" value="Continue"/> + </div> + </form> + </div> +</div> diff -r a0a4f15fe0958c5ff2658c1695c63023b9cf6d39 -r db2bf800496478a5ea041480c3c514c2620e28ae templates/admin/tool_shed_repository/deactivate_or_uninstall_repository.mako --- 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. </div><div class="toolParamHelp" style="clear: both;"> - * 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'. </div> %endif %if repository.includes_datatypes: diff -r a0a4f15fe0958c5ff2658c1695c63023b9cf6d39 -r db2bf800496478a5ea041480c3c514c2620e28ae templates/admin/tool_shed_repository/install_missing_tool_dependencies.mako --- 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 %> - -<br/><br/> -<ul class="manage-table-actions"> - <li><a class="action-button" id="repository-${repository.id}-popup" class="menubutton">Repository Actions</a></li> - <div popupmenu="repository-${repository.id}-popup"> - <a class="action-button" href="${h.url_for( controller='admin_toolshed', action='browse_repository', id=trans.security.encode_id( repository.id ) )}">Browse repository files</a> - <a class="action-button" href="${h.url_for( controller='admin_toolshed', action='manage_repository', id=trans.security.encode_id( repository.id ) )}">Manage repository</a> - <a class="action-button" href="${h.url_for( controller='admin_toolshed', action='check_for_updates', id=trans.security.encode_id( repository.id ) )}">Get updates</a> - %if repository.includes_tools: - <a class="action-button" href="${h.url_for( controller='admin_toolshed', action='set_tool_versions', id=trans.security.encode_id( repository.id ) )}">Set tool versions</a> - %endif - %if repository.tool_dependencies: - <a class="action-button" href="${h.url_for( controller='admin_toolshed', action='manage_tool_dependencies', id=trans.security.encode_id( repository.id ) )}">Manage tool dependencies</a> - %endif - <a class="action-button" href="${h.url_for( controller='admin_toolshed', action='deactivate_or_uninstall_repository', id=trans.security.encode_id( repository.id ) )}">Deactivate or uninstall repository</a> - </div> -</ul> - -%if message: - ${render_msg( message, status )} -%endif - -<div class="warningmessage"> - <p> - 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. - </p> -</div> -<br/> -<div class="warningmessage"> - <p> - Installation may take a while. <b>Always wait until a message is displayed in your browser after clicking the <b>Go</b> button below.</b> - If you get bored, watching your Galaxy server's paster log will help pass the time. - </p> - <p> - 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}/<i>package name</i>/<i>package version</i>/${repository.owner}/${repository.name}/${repository.changeset_revision} - </p> -</div> -<br/> - -<div class="toolForm"> - <div class="toolFormBody"> - <form name="install_missing_tool_dependencies" id="install_missing_tool_dependencies" action="${h.url_for( controller='admin_toolshed', action='install_missing_tool_dependencies', id=trans.security.encode_id( repository.id ), tool_panel_section=tool_panel_section, new_tool_panel_section=new_tool_panel_section, reinstalling=reinstalling )}" method="post" > - <div style="clear: both"></div> - <div class="form-row"> - <label>Install missing tool dependencies?</label> - ${install_tool_dependencies_check_box.get_html()} - <div class="toolParamHelp" style="clear: both;"> - Un-check to skip installation of these missing tool dependencies. - </div> - ## Fake the no_changes_check_box value. - %if no_changes_checked: - <input type="hidden" id="no_changes" name="no_changes" value="true" checked="checked"><input type="hidden" name="no_changes" value="true"> - %else: - <input type="hidden" name="no_changes" value="true"> - %endif - </div> - <div style="clear: both"></div> - <div class="form-row"> - <table class="grid"> - <tr><td colspan="4" bgcolor="#D8D8D8"><b>Missing tool dependencies</b></td></tr> - <tr> - <th>Name</th> - <th>Version</th> - <th>Type</th> - <th>Install directory</th> - </tr> - %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 ): - <tr> - <td>${name}</td> - <td>${version}</td> - <td>${type}</td> - <td>${install_dir}</td> - </tr> - %if readme_text: - <tr><td colspan="4" bgcolor="#FFFFCC">${name} ${version} requirements and installation information</td></tr> - <tr><td colspan="4"><pre>${readme_text}</pre></td></tr> - %endif - %endif - %endfor - </table> - <div style="clear: both"></div> - </div> - <div class="form-row"> - <input type="submit" name="install_missing_tool_dependencies_button" value="Go"/> - </div> - </form> - </div> -</div> diff -r a0a4f15fe0958c5ff2658c1695c63023b9cf6d39 -r db2bf800496478a5ea041480c3c514c2620e28ae templates/admin/tool_shed_repository/install_tool_dependencies.mako --- a/templates/admin/tool_shed_repository/install_tool_dependencies.mako +++ b/templates/admin/tool_shed_repository/install_tool_dependencies.mako @@ -25,16 +25,7 @@ <div class="toolForm"><div class="toolFormBody"> - <form name="install_tool_dependenceies" id="install_tool_dependenceies" action="${h.url_for( controller='admin_toolshed', action='install_repository', tool_shed_url=tool_shed_url, repo_info_dict=repo_info_dict, includes_tools=includes_tools )}" method="post" > - <div style="clear: both"></div> - <div class="form-row"> - <label>Install tool dependencies?</label> - ${install_tool_dependencies_check_box.get_html()} - <div class="toolParamHelp" style="clear: both;"> - Un-check to skip automatic installation of these tool dependencies. - </div> - </div> - <div style="clear: both"></div> + <form name="install_tool_dependenceies" id="install_tool_dependenceies" action="${h.url_for( controller='admin_toolshed', action='install_tool_dependencies' )}" method="post" ><div class="form-row"><table class="grid"><tr><td colspan="4" bgcolor="#D8D8D8"><b>Tool dependencies</b></td></tr> @@ -44,42 +35,46 @@ <th>Type</th><th>Install directory</th></tr> - %for repository_name, repo_info_tuple in dict_with_tool_dependencies.items(): + <% tool_shed_repository = None %> + %for tool_dependency in tool_dependencies: + <input type="hidden" name="tool_dependency_ids" value="${trans.security.encode_id( tool_dependency.id )}"/><% - 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 ): - <tr> - <td>${name}</td> - <td>${version}</td> - <td>${type}</td> - <td>${install_dir}</td> - </tr> - %if readme_text: - <tr><td colspan="4" bgcolor="#FFFFCC">${name} ${version} requirements and installation information</td></tr> - <tr><td colspan="4"><pre>${readme_text}</pre></td></tr> - %endif + %if not os.path.exists( install_dir ): + <tr> + <td>${tool_dependency.name}</td> + <td>${tool_dependency.version}</td> + <td>${tool_dependency.type}</td> + <td>${install_dir}</td> + </tr> + %if readme_text: + <tr><td colspan="4" bgcolor="#FFFFCC">${tool_dependency.name} ${tool_dependency.version} requirements and installation information</td></tr> + <tr><td colspan="4"><pre>${readme_text}</pre></td></tr> %endif - %endfor + %endif %endfor </table><div style="clear: both"></div></div><div class="form-row"> - <input type="submit" name="install_tool_dependenceies_button" value="Continue"/> + <input type="submit" name="install_tool_dependencies_button" value="Install"/></div></form></div> diff -r a0a4f15fe0958c5ff2658c1695c63023b9cf6d39 -r db2bf800496478a5ea041480c3c514c2620e28ae templates/admin/tool_shed_repository/manage_repository.mako --- a/templates/admin/tool_shed_repository/manage_repository.mako +++ b/templates/admin/tool_shed_repository/manage_repository.mako @@ -12,10 +12,8 @@ <a class="action-button" href="${h.url_for( controller='admin_toolshed', action='set_tool_versions', id=trans.security.encode_id( repository.id ) )}">Set tool versions</a> %endif %if repository.tool_dependencies: - <a class="action-button" href="${h.url_for( controller='admin_toolshed', action='manage_tool_dependencies', id=trans.security.encode_id( repository.id ) )}">Manage tool dependencies</a> - %endif - %if repository.missing_tool_dependencies: - <a class="action-button" href="${h.url_for( controller='admin_toolshed', action='install_missing_tool_dependencies', id=trans.security.encode_id( repository.id ) )}">Install missing tool dependencies</a> + <% tool_dependency_ids = [ trans.security.encode_id( td.id ) for td in repository.tool_dependencies ] %> + <a class="action-button" href="${h.url_for( controller='admin_toolshed', action='manage_tool_dependencies', tool_dependency_ids=tool_dependency_ids )}">Manage tool dependencies</a> %endif <a class="action-button" href="${h.url_for( controller='admin_toolshed', action='deactivate_or_uninstall_repository', id=trans.security.encode_id( repository.id ) )}">Deactivate or uninstall repository</a></div> @@ -91,21 +89,15 @@ <td><b>version</b></td><td><b>type</b></td></tr> - %for index, missing_dependency_tup in enumerate( missing_tool_dependencies ): - <% name, version, type = missing_dependency_tup %> + %for tool_dependency in missing_tool_dependencies: <tr><td> - <div style="float: left; margin-left: 1px;" class="menubutton split popup" id="missing_dependency-${index}-popup"> - <a class="view-info" href="${h.url_for( controller='admin_toolshed', action='install_tool_dependency', name=name, version=version, type=type, repository_id=trans.security.encode_id( repository.id ) )}"> - ${name} - </a> - </div> - <div popupmenu="missing_dependency-${index}-popup"> - <a class="action-button" href="${h.url_for( controller='admin_toolshed', action='install_tool_dependency', name=name, version=version, type=type, repository_id=trans.security.encode_id( repository.id ) )}">Install this dependency</a> - </div> + <a class="view-info" href="${h.url_for( controller='admin_toolshed', action='manage_tool_dependencies', id=trans.security.encode_id( tool_dependency.id ) )}"> + ${tool_dependency.name} + </a></td> - <td>${version}</td> - <td>${type}</td> + <td>${tool_dependency.version}</td> + <td>${tool_dependency.type}</td></tr> %endfor </table> @@ -131,14 +123,9 @@ %for installed_tool_dependency in installed_tool_dependencies: <tr><td> - <div style="float: left; margin-left: 1px;" class="menubutton split popup" id="dependency-${installed_tool_dependency.id}-popup"> - <a class="view-info" href="${h.url_for( controller='admin_toolshed', action='browse_tool_dependency', id=trans.security.encode_id( installed_tool_dependency.id ), repository_id=trans.security.encode_id( repository.id ) )}"> - ${installed_tool_dependency.name} - </a> - </div> - <div popupmenu="dependency-${installed_tool_dependency.id}-popup"> - <a class="action-button" href="${h.url_for( controller='admin_toolshed', action='uninstall_tool_dependency', id=trans.security.encode_id( installed_tool_dependency.id ), repository_id=trans.security.encode_id( repository.id ) )}">Uninstall this dependency</a> - </div> + <a class="view-info" href="${h.url_for( controller='admin_toolshed', action='browse_tool_dependency', id=trans.security.encode_id( installed_tool_dependency.id ), repository_id=trans.security.encode_id( repository.id ) )}"> + ${installed_tool_dependency.name} + </a></td><td>${installed_tool_dependency.version}</td><td>${installed_tool_dependency.type}</td> diff -r a0a4f15fe0958c5ff2658c1695c63023b9cf6d39 -r db2bf800496478a5ea041480c3c514c2620e28ae templates/admin/tool_shed_repository/manage_tool_dependencies.mako --- 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: <a class="action-button" href="${h.url_for( controller='admin_toolshed', action='set_tool_versions', id=trans.security.encode_id( repository.id ) )}">Set tool versions</a> %endif - %if repository.missing_tool_dependencies: - <a class="action-button" href="${h.url_for( controller='admin_toolshed', action='install_missing_tool_dependencies', id=trans.security.encode_id( repository.id ) )}">Install missing tool dependencies</a> - %endif <a class="action-button" href="${h.url_for( controller='admin_toolshed', action='deactivate_or_uninstall_repository', id=trans.security.encode_id( repository.id ) )}">Deactivate or uninstall repository</a></div></ul> @@ -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 ) %><tr><td bgcolor="#D8D8D8"><div style="float: left; margin-left: 1px;" class="menubutton split popup" id="dependency-${tool_dependency.id}-popup"> - %if uninstalled: - <a class="view-info" href="${h.url_for( controller='admin_toolshed', action='install_tool_dependency', name=name, version=version, type=type, repository_id=trans.security.encode_id( repository.id ) )}"> + %if not installed: + <a class="view-info" href="${h.url_for( controller='admin_toolshed', action='manage_tool_dependencies', operation='browse', tool_dependency_id=trans.security.encode_id( tool_dependency.id ) )}"><b>Name</b></a><div popupmenu="dependency-${tool_dependency.id}-popup"> - <a class="action-button" href="${h.url_for( controller='admin_toolshed', action='install_tool_dependency', name=name, version=version, type=type, repository_id=trans.security.encode_id( repository.id ) )}">Install this dependency</a> + <a class="action-button" href="${h.url_for( controller='admin_toolshed', action='manage_tool_dependencies', operation='install', tool_dependency_id=trans.security.encode_id( tool_dependency.id ) )}">Install this tool dependency</a></div> %else: - <a class="view-info" href="${h.url_for( controller='admin_toolshed', action='browse_tool_dependency', id=trans.security.encode_id( tool_dependency.id ), repository_id=trans.security.encode_id( repository.id ) )}"> + <a class="view-info" href="${h.url_for( controller='admin_toolshed', action='manage_tool_dependencies', operation='browse', tool_dependency_id=trans.security.encode_id( tool_dependency.id ) )}"><b>Name</b></a><div popupmenu="dependency-${tool_dependency.id}-popup"> - <a class="action-button" href="${h.url_for( controller='admin_toolshed', action='uninstall_tool_dependency', id=trans.security.encode_id( tool_dependency.id ), repository_id=trans.security.encode_id( repository.id ) )}">Uninstall this dependency</a> + <a class="action-button" href="${h.url_for( controller='admin_toolshed', action='manage_tool_dependencies', operation='uninstall', tool_dependency_id=trans.security.encode_id( tool_dependency.id ) )}">Uninstall this tool dependency</a></div> %endif </div> @@ -64,7 +61,7 @@ <tr><th>Install directory</th><td> - %if uninstalled: + %if not installed: This dependency is not currently installed %else: <a class="view-info" href="${h.url_for( controller='admin_toolshed', action='browse_tool_dependency', id=trans.security.encode_id( tool_dependency.id ), repository_id=trans.security.encode_id( repository.id ) )}"> @@ -73,7 +70,7 @@ %endif </td></tr> - <tr><th>Uninstalled</th><td>${uninstalled}</td></tr> + <tr><th>Installed</th><td>${not installed}</td></tr> %endfor </table><div style="clear: both"></div> diff -r a0a4f15fe0958c5ff2658c1695c63023b9cf6d39 -r db2bf800496478a5ea041480c3c514c2620e28ae templates/admin/tool_shed_repository/reselect_tool_panel_section.mako --- 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 @@ <div class="toolForm"><div class="toolFormTitle">Choose the tool panel section to contain the installed tools (optional)</div><div class="toolFormBody"> - %if repository.includes_tool_dependencies: - <form name="reselect_tool_panel_section" id="reselect_tool_panel_section" action="${h.url_for( controller='admin_toolshed', action='install_missing_tool_dependencies', id=trans.security.encode_id( repository.id ), reinstalling=True )}" method="post" > + %if repository.tool_dependencies: + <% tool_dependency_ids = [ trans.security.encode_id( td.id ) for td in repository.tool_dependencies ] %> + <form name="reselect_tool_panel_section" id="reselect_tool_panel_section" action="${h.url_for( controller='admin_toolshed', action='manage_tool_dependencies', operation='install', tool_dependency_ids=tool_dependency_ids )}" method="post" > %else: <form name="reselect_tool_panel_section" id="reselect_tool_panel_section" action="${h.url_for( controller='admin_toolshed', action='reinstall_repository', id=trans.security.encode_id( repository.id ) )}" method="post" > %endif diff -r a0a4f15fe0958c5ff2658c1695c63023b9cf6d39 -r db2bf800496478a5ea041480c3c514c2620e28ae templates/admin/tool_shed_repository/select_tool_panel_section.mako --- 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 @@ <div class="toolForm"><div class="toolFormTitle">Repository README file (may contain important installation or license information)</div><div class="toolFormBody"> + <input type="hidden" name="readme_text" value="${readme_text}"/><div class="form-row"><pre>${readme_text}</pre></div> diff -r a0a4f15fe0958c5ff2658c1695c63023b9cf6d39 -r db2bf800496478a5ea041480c3c514c2620e28ae templates/admin/tool_shed_repository/tool_dependencies_grid.mako --- /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()} +</%def> diff -r a0a4f15fe0958c5ff2658c1695c63023b9cf6d39 -r db2bf800496478a5ea041480c3c514c2620e28ae templates/admin/tool_shed_repository/tool_dependency_installation_status.mako --- /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 = '<div class="count-box state-color-%s" id="ToolDependencyStatus-%s">' % ( bgcolor, trans.security.encode_id( tool_dependency.id ) ) + rval += '%s</div>' % tool_dependency.status + else: + rval = tool_dependency.status + %> + ${rval} +</%def> + +${render_tool_dependency_status( tool_dependency )} diff -r a0a4f15fe0958c5ff2658c1695c63023b9cf6d39 -r db2bf800496478a5ea041480c3c514c2620e28ae templates/admin/tool_shed_repository/uninstall_tool_dependencies.mako --- /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 + +<div class="toolForm"> + <div class="toolFormTitle">Uninstall tool dependencies</div> + <div class="toolFormBody"> + <form name="uninstall_tool_dependenceies" id="uninstall_tool_dependenceies" action="${h.url_for( controller='admin_toolshed', action='uninstall_tool_dependencies' )}" method="post" > + <div class="form-row"> + <table class="grid"> + <tr> + <th>Name</th> + <th>Version</th> + <th>Type</th> + <th>Install directory</th> + </tr> + %for tool_dependency in tool_dependencies: + <input type="hidden" name="tool_dependency_ids" value="${trans.security.encode_id( tool_dependency.id )}"/> + <% + 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 ): + <tr> + <td>${tool_dependency.name}</td> + <td>${tool_dependency.version}</td> + <td>${tool_dependency.type}</td> + <td>${install_dir}</td> + </tr> + %endif + %endfor + </table> + <div style="clear: both"></div> + </div> + <div class="form-row"> + <input type="submit" name="uninstall_tool_dependencies_button" value="Uninstall"/> + <div class="toolParamHelp" style="clear: both;"> + Click to uninstall the tool dependencies listed above. + </div> + </div> + </form> + </div> +</div> diff -r a0a4f15fe0958c5ff2658c1695c63023b9cf6d39 -r db2bf800496478a5ea041480c3c514c2620e28ae templates/tool_form.mako --- 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 <div class="toolForm" id="${tool.id}"> Repository URL: https://bitbucket.org/galaxy/galaxy-central/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email.