1 new commit in galaxy-central: https://bitbucket.org/galaxy/galaxy-central/commits/ab20415126a7/ Changeset: ab20415126a7 User: greg Date: 2013-09-20 17:05:30 Summary: Additional framework support for tool dependencies that define binary installation recipes. This change set also includes several fixes, including fixes for discovering and displaying installed and missing tool dependencies when installing a repository, fixes for the remaining issue that resulted in the creation of a so-called "white ghost" when reinstalling a repository that defines certain dependencies. Affected #: 15 files diff -r 93215e7e74d020b478803ce2755f76c7e5236f16 -r ab20415126a768f456314cfe587e4ce71fd2049b lib/galaxy/model/__init__.py --- a/lib/galaxy/model/__init__.py +++ b/lib/galaxy/model/__init__.py @@ -25,7 +25,7 @@ from galaxy.datatypes.metadata import MetadataCollection from galaxy.model.item_attrs import Dictifiable, UsesAnnotations from galaxy.security import get_permitted_actions -from galaxy.util import is_multi_byte, nice_size, Params, restore_text, send_mail +from galaxy.util import asbool, is_multi_byte, nice_size, Params, restore_text, send_mail from galaxy.util.bunch import Bunch from galaxy.util.hash_util import new_secure_hash from galaxy.web.framework.helpers import to_unicode @@ -34,6 +34,7 @@ WorkflowMappingField) from sqlalchemy.orm import object_session from sqlalchemy.sql.expression import func +from tool_shed.util import common_util log = logging.getLogger( __name__ ) @@ -3463,7 +3464,28 @@ @property def has_repository_dependencies( self ): if self.metadata: - return 'repository_dependencies' in self.metadata + repository_dependencies_dict = self.metadata.get( 'repository_dependencies', {} ) + repository_dependencies = repository_dependencies_dict.get( 'repository_dependencies', [] ) + # [["http://localhost:9009", "package_libgtextutils_0_6", "test", "e2003cbf18cd", "True", "True"]] + for rd_tup in repository_dependencies: + tool_shed, name, owner, changeset_revision, prior_installation_required, only_if_compiling_contained_td = \ + common_util.parse_repository_dependency_tuple( rd_tup ) + if not asbool( only_if_compiling_contained_td ): + return True + return False + + @property + def has_repository_dependencies_only_if_compiling_contained_td( self ): + if self.metadata: + repository_dependencies_dict = self.metadata.get( 'repository_dependencies', {} ) + repository_dependencies = repository_dependencies_dict.get( 'repository_dependencies', [] ) + # [["http://localhost:9009", "package_libgtextutils_0_6", "test", "e2003cbf18cd", "True", "True"]] + for rd_tup in repository_dependencies: + tool_shed, name, owner, changeset_revision, prior_installation_required, only_if_compiling_contained_td = \ + common_util.parse_repository_dependency_tuple( rd_tup ) + if not asbool( only_if_compiling_contained_td ): + return False + return True return False @property @@ -3695,10 +3717,14 @@ @property def tuples_of_repository_dependencies_needed_for_compiling_td( self ): - """Return this repository's repository dependencies that are necessary only for compiling this repository's tool dependencies.""" + """ + Return tuples defining this repository's repository dependencies that are necessary only for compiling this repository's tool + dependencies. + """ rd_tups_of_repositories_needed_for_compiling_td = [] - if self.has_repository_dependencies: - rd_tups = self.metadata[ 'repository_dependencies' ][ 'repository_dependencies' ] + if self.metadata: + repository_dependencies = self.metadata.get( 'repository_dependencies', None ) + rd_tups = repository_dependencies[ 'repository_dependencies' ] for rd_tup in rd_tups: if len( rd_tup ) == 6: tool_shed, name, owner, changeset_revision, prior_installation_required, only_if_compiling_contained_td = rd_tup diff -r 93215e7e74d020b478803ce2755f76c7e5236f16 -r ab20415126a768f456314cfe587e4ce71fd2049b lib/galaxy/webapps/galaxy/controllers/admin_toolshed.py --- a/lib/galaxy/webapps/galaxy/controllers/admin_toolshed.py +++ b/lib/galaxy/webapps/galaxy/controllers/admin_toolshed.py @@ -812,7 +812,7 @@ status = kwd.get( 'status', 'done' ) shed_tool_conf = kwd.get( 'shed_tool_conf', None ) tool_shed_url = kwd[ 'tool_shed_url' ] - # Handle repository dependencies. + # Handle repository dependencies, which do not include those that are required only for compiling a dependent repository's tool dependencies. has_repository_dependencies = util.string_as_bool( kwd.get( 'has_repository_dependencies', False ) ) install_repository_dependencies = kwd.get( 'install_repository_dependencies', '' ) # Every repository will be installed into the same tool panel section or all will be installed outside of any sections. @@ -1061,7 +1061,7 @@ repository_clone_url, metadata, trans.model.ToolShedRepository.installation_status.NEW, - tool_shed_repository.installed_changeset_revision, + tool_shed_repository.changeset_revision, tool_shed_repository.owner, tool_shed_repository.dist_to_shed ) ctx_rev = suc.get_ctx_rev( trans.app, @@ -1320,7 +1320,6 @@ missing_tool_dependencies = dependencies_for_repository_dict.get( 'missing_tool_dependencies', None ) repository_name = dependencies_for_repository_dict.get( 'name', None ) repository_owner = dependencies_for_repository_dict.get( 'repository_owner', None ) - if installed_repository_dependencies or missing_repository_dependencies: has_repository_dependencies = True else: diff -r 93215e7e74d020b478803ce2755f76c7e5236f16 -r ab20415126a768f456314cfe587e4ce71fd2049b lib/galaxy/webapps/tool_shed/api/repositories.py --- a/lib/galaxy/webapps/tool_shed/api/repositories.py +++ b/lib/galaxy/webapps/tool_shed/api/repositories.py @@ -73,6 +73,7 @@ "changeset_revision": "3a08cc21466f", "downloadable": true, "has_repository_dependencies": false, + "has_repository_dependencies_only_if_compiling_contained_td": false, "id": "f9cad7b01a472135", "includes_datatypes": false, "includes_tool_dependencies": false, @@ -125,7 +126,8 @@ action='show', id=encoded_repository_metadata_id ) # Get the repo_info_dict for installing the repository. - repo_info_dict, includes_tools, includes_tool_dependencies, includes_tools_for_display_in_tool_panel, has_repository_dependencies = \ + repo_info_dict, includes_tools, includes_tool_dependencies, includes_tools_for_display_in_tool_panel, \ + has_repository_dependencies, has_repository_dependencies_only_if_compiling_contained_td = \ repository_util.get_repo_info_dict( trans, encoded_repository_id, changeset_revision ) return repository_dict, repository_metadata_dict, repo_info_dict else: diff -r 93215e7e74d020b478803ce2755f76c7e5236f16 -r ab20415126a768f456314cfe587e4ce71fd2049b lib/galaxy/webapps/tool_shed/controllers/repository.py --- a/lib/galaxy/webapps/tool_shed/controllers/repository.py +++ b/lib/galaxy/webapps/tool_shed/controllers/repository.py @@ -1343,32 +1343,36 @@ def get_changeset_revision_and_ctx_rev( self, trans, **kwd ): """Handle a request from a local Galaxy instance to retrieve the changeset revision hash to which an installed repository can be updated.""" def has_galaxy_utilities( repository_metadata ): - includes_data_managers = False - includes_datatypes = False - includes_tools = False - includes_tools_for_display_in_tool_panel = False - has_repository_dependencies = False - includes_tool_dependencies = False - includes_workflows = False + has_galaxy_utilities_dict = dict( includes_data_managers=False, + includes_datatypes=False, + includes_tools=False, + includes_tools_for_display_in_tool_panel=False, + has_repository_dependencies=False, + has_repository_dependencies_only_if_compiling_contained_td=False, + includes_tool_dependencies=False, + includes_workflows=False ) if repository_metadata: includes_tools_for_display_in_tool_panel = repository_metadata.includes_tools_for_display_in_tool_panel metadata = repository_metadata.metadata if metadata: if 'data_manager' in metadata: - includes_data_managers = True + has_galaxy_utilities_dict[ 'includes_data_managers' ] = True if 'datatypes' in metadata: - includes_datatypes = True + has_galaxy_utilities_dict[ 'includes_datatypes' ] = True if 'tools' in metadata: - includes_tools = True + has_galaxy_utilities_dict[ 'includes_tools' ] = True if 'tool_dependencies' in metadata: - includes_tool_dependencies = True - if 'repository_dependencies' in metadata: - has_repository_dependencies = True + has_galaxy_utilities_dict[ 'includes_tool_dependencies' ] = True + repository_dependencies_dict = metadata.get( 'repository_dependencies', {} ) + repository_dependencies = repository_dependencies_dict.get( 'repository_dependencies', [] ) + has_repository_dependencies, has_repository_dependencies_only_if_compiling_contained_td = \ + suc.get_repository_dependency_types( repository_dependencies ) + has_galaxy_utilities_dict[ 'has_repository_dependencies' ] = has_repository_dependencies + has_galaxy_utilities_dict[ 'has_repository_dependencies_only_if_compiling_contained_td' ] = \ + has_repository_dependencies_only_if_compiling_contained_td if 'workflows' in metadata: - includes_workflows = True - return includes_data_managers, includes_datatypes, includes_tools, includes_tools_for_display_in_tool_panel, includes_tool_dependencies, has_repository_dependencies, includes_workflows - message = kwd.get( 'message', '' ) - status = kwd.get( 'status', 'done' ) + has_galaxy_utilities_dict[ 'includes_workflows' ] = True + return has_galaxy_utilities_dict name = kwd.get( 'name', None ) owner = kwd.get( 'owner', None ) changeset_revision = kwd.get( 'changeset_revision', None ) @@ -1376,8 +1380,15 @@ repository_metadata = suc.get_repository_metadata_by_changeset_revision( trans, trans.security.encode_id( repository.id ), changeset_revision ) - includes_data_managers, includes_datatypes, includes_tools, includes_tools_for_display_in_tool_panel, includes_tool_dependencies, has_repository_dependencies, includes_workflows = \ - has_galaxy_utilities( repository_metadata ) + has_galaxy_utilities_dict = has_galaxy_utilities( repository_metadata ) + includes_data_managers = has_galaxy_utilities_dict[ 'includes_data_managers' ] + includes_datatypes = has_galaxy_utilities_dict[ 'includes_datatypes' ] + includes_tools = has_galaxy_utilities_dict[ 'includes_tools' ] + includes_tools_for_display_in_tool_panel = has_galaxy_utilities_dict[ 'includes_tools_for_display_in_tool_panel' ] + includes_tool_dependencies = has_galaxy_utilities_dict[ 'includes_tool_dependencies' ] + has_repository_dependencies = has_galaxy_utilities_dict[ 'has_repository_dependencies' ] + has_repository_dependencies_only_if_compiling_contained_td = has_galaxy_utilities_dict[ 'has_repository_dependencies_only_if_compiling_contained_td' ] + includes_workflows = has_galaxy_utilities_dict[ 'includes_workflows' ] repo_dir = repository.repo_path( trans.app ) repo = hg.repository( suc.get_configured_ui(), repo_dir ) # Default to the received changeset revision and ctx_rev. @@ -1392,6 +1403,7 @@ includes_tools_for_display_in_tool_panel=includes_tools_for_display_in_tool_panel, includes_tool_dependencies=includes_tool_dependencies, has_repository_dependencies=has_repository_dependencies, + has_repository_dependencies_only_if_compiling_contained_td=has_repository_dependencies_only_if_compiling_contained_td, includes_workflows=includes_workflows ) if changeset_revision == repository.tip( trans.app ): # If changeset_revision is the repository tip, there are no additional updates. @@ -1407,6 +1419,7 @@ for changeset in repo.changelog: includes_tools = False has_repository_dependencies = False + has_repository_dependencies_only_if_compiling_contained_td = False changeset_hash = str( repo.changectx( changeset ) ) ctx = suc.get_changectx_for_changeset( repo, changeset_hash ) if update_to_changeset_hash: @@ -1414,8 +1427,15 @@ trans.security.encode_id( repository.id ), changeset_hash ) if update_to_repository_metadata: - includes_data_managers, includes_datatypes, includes_tools, includes_tools_for_display_in_tool_panel, includes_tool_dependencies, has_repository_dependencies, includes_workflows = \ - has_galaxy_utilities( update_to_repository_metadata ) + has_galaxy_utilities_dict = has_galaxy_utilities( repository_metadata ) + includes_data_managers = has_galaxy_utilities_dict[ 'includes_data_managers' ] + includes_datatypes = has_galaxy_utilities_dict[ 'includes_datatypes' ] + includes_tools = has_galaxy_utilities_dict[ 'includes_tools' ] + includes_tools_for_display_in_tool_panel = has_galaxy_utilities_dict[ 'includes_tools_for_display_in_tool_panel' ] + includes_tool_dependencies = has_galaxy_utilities_dict[ 'includes_tool_dependencies' ] + has_repository_dependencies = has_galaxy_utilities_dict[ 'has_repository_dependencies' ] + has_repository_dependencies_only_if_compiling_contained_td = has_galaxy_utilities_dict[ 'has_repository_dependencies_only_if_compiling_contained_td' ] + includes_workflows = has_galaxy_utilities_dict[ 'includes_workflows' ] # We found a RepositoryMetadata record. if changeset_hash == repository.tip( trans.app ): # The current ctx is the repository tip, so use it. @@ -1435,6 +1455,7 @@ update_dict[ 'includes_tool_dependencies' ] = includes_tool_dependencies update_dict[ 'includes_workflows' ] = includes_workflows update_dict[ 'has_repository_dependencies' ] = has_repository_dependencies + update_dict[ 'has_repository_dependencies_only_if_compiling_contained_td' ] = has_repository_dependencies_only_if_compiling_contained_td update_dict[ 'changeset_revision' ] = str( latest_changeset_revision ) update_dict[ 'ctx_rev' ] = str( update_to_ctx.rev() ) return encoding_util.tool_shed_encode( update_dict ) @@ -1611,14 +1632,18 @@ includes_tools = False includes_tools_for_display_in_tool_panel = False has_repository_dependencies = False + has_repository_dependencies_only_if_compiling_contained_td = False includes_tool_dependencies = False repo_info_dicts = [] for tup in zip( util.listify( repository_ids ), util.listify( changeset_revisions ) ): repository_id, changeset_revision = tup - repo_info_dict, cur_includes_tools, cur_includes_tool_dependencies, cur_includes_tools_for_display_in_tool_panel, cur_has_repository_dependencies = \ + repo_info_dict, cur_includes_tools, cur_includes_tool_dependencies, cur_includes_tools_for_display_in_tool_panel, \ + cur_has_repository_dependencies, cur_has_repository_dependencies_only_if_compiling_contained_td = \ repository_util.get_repo_info_dict( trans, repository_id, changeset_revision ) if cur_has_repository_dependencies and not has_repository_dependencies: has_repository_dependencies = True + if cur_has_repository_dependencies_only_if_compiling_contained_td and not has_repository_dependencies_only_if_compiling_contained_td: + has_repository_dependencies_only_if_compiling_contained_td = True if cur_includes_tools and not includes_tools: includes_tools = True if cur_includes_tool_dependencies and not includes_tool_dependencies: @@ -1629,6 +1654,7 @@ return dict( includes_tools=includes_tools, includes_tools_for_display_in_tool_panel=includes_tools_for_display_in_tool_panel, has_repository_dependencies=has_repository_dependencies, + has_repository_dependencies_only_if_compiling_contained_td=has_repository_dependencies_only_if_compiling_contained_td, includes_tool_dependencies=includes_tool_dependencies, repo_info_dicts=repo_info_dicts ) @@ -1708,7 +1734,9 @@ tool_version_dicts = [] for changeset in repo.changelog: current_changeset_revision = str( repo.changectx( changeset ) ) - repository_metadata = suc.get_repository_metadata_by_changeset_revision( trans, trans.security.encode_id( repository.id ), current_changeset_revision ) + repository_metadata = suc.get_repository_metadata_by_changeset_revision( trans, + trans.security.encode_id( repository.id ), + current_changeset_revision ) if repository_metadata and repository_metadata.tool_versions: tool_version_dicts.append( repository_metadata.tool_versions ) if current_changeset_revision == changeset_revision: @@ -1766,22 +1794,30 @@ includes_workflows = True readme_files_dict = readme_util.build_readme_files_dict( metadata ) # See if the repo_info_dict was populated with repository_dependencies or tool_dependencies. + has_repository_dependencies = False + has_repository_dependencies_only_if_compiling_contained_td = False + includes_tool_dependencies = False for name, repo_info_tuple in repo_info_dict.items(): - description, repository_clone_url, changeset_revision, ctx_rev, repository_owner, repository_dependencies, tool_dependencies = \ - suc.get_repo_info_tuple_contents( repo_info_tuple ) - if repository_dependencies: - has_repository_dependencies = True - else: - has_repository_dependencies = False - if tool_dependencies: - includes_tool_dependencies = True - else: - includes_tool_dependencies = False + if not has_repository_dependencies or not has_repository_dependencies_only_if_compiling_contained_td or not includes_tool_dependencies: + description, repository_clone_url, changeset_revision, ctx_rev, repository_owner, repository_dependencies, tool_dependencies = \ + suc.get_repo_info_tuple_contents( repo_info_tuple ) + for rd_key, rd_tups in repository_dependencies.items(): + if rd_key in [ 'root_key', 'description' ]: + continue + curr_has_repository_dependencies, curr_has_repository_dependencies_only_if_compiling_contained_td = \ + suc.get_repository_dependency_types( rd_tups ) + if curr_has_repository_dependencies and not has_repository_dependencies: + has_repository_dependencies = True + if curr_has_repository_dependencies_only_if_compiling_contained_td and not has_repository_dependencies_only_if_compiling_contained_td: + has_repository_dependencies_only_if_compiling_contained_td = True + if tool_dependencies and not includes_tool_dependencies: + includes_tool_dependencies = True return dict( includes_data_managers=includes_data_managers, includes_datatypes=includes_datatypes, includes_tools=includes_tools, includes_tools_for_display_in_tool_panel=includes_tools_for_display_in_tool_panel, has_repository_dependencies=has_repository_dependencies, + has_repository_dependencies_only_if_compiling_contained_td=has_repository_dependencies_only_if_compiling_contained_td, includes_tool_dependencies=includes_tool_dependencies, includes_workflows=includes_workflows, readme_files_dict=readme_files_dict, @@ -2434,7 +2470,9 @@ try: commands.remove( repo.ui, repo, selected_file, force=True ) except Exception, e: - log.debug( "Error removing files using the mercurial API, so trying a different approach, the error was: %s" % str( e )) + log.debug( "Error removing the following file using the mercurial API:\n %s" % str( selected_file ) ) + log.debug( "The error was: %s" % str( e )) + log.debug( "Attempting to remove the file using a different approach." ) relative_selected_file = selected_file.split( 'repo_%d' % repository.id )[1].lstrip( '/' ) repo.dirstate.remove( relative_selected_file ) repo.dirstate.write() diff -r 93215e7e74d020b478803ce2755f76c7e5236f16 -r ab20415126a768f456314cfe587e4ce71fd2049b lib/galaxy/webapps/tool_shed/model/__init__.py --- a/lib/galaxy/webapps/tool_shed/model/__init__.py +++ b/lib/galaxy/webapps/tool_shed/model/__init__.py @@ -253,6 +253,7 @@ self.time_last_tested = time_last_tested self.tool_test_results = tool_test_results self.has_repository_dependencies = has_repository_dependencies + # We don't consider the special case has_repository_dependencies_only_if_compiling_contained_td here. self.includes_datatypes = includes_datatypes self.includes_tools = includes_tools self.includes_tool_dependencies = includes_tool_dependencies diff -r 93215e7e74d020b478803ce2755f76c7e5236f16 -r ab20415126a768f456314cfe587e4ce71fd2049b lib/tool_shed/galaxy_install/repository_util.py --- a/lib/tool_shed/galaxy_install/repository_util.py +++ b/lib/tool_shed/galaxy_install/repository_util.py @@ -234,10 +234,10 @@ else: includes_tools = False includes_tools_for_display_in_tool_panel = repository_metadata.includes_tools_for_display_in_tool_panel - if 'repository_dependencies' in metadata: - has_repository_dependencies = True - else: - has_repository_dependencies = False + repository_dependencies_dict = metadata.get( 'repository_dependencies', {} ) + repository_dependencies = repository_dependencies_dict.get( 'repository_dependencies', [] ) + has_repository_dependencies, has_repository_dependencies_only_if_compiling_contained_td = \ + suc.get_repository_dependency_types( repository_dependencies ) if 'tool_dependencies' in metadata: includes_tool_dependencies = True else: @@ -246,6 +246,7 @@ # Here's where we may have to handle enhancements to the callers. See above comment. includes_tools = False has_repository_dependencies = False + has_repository_dependencies_only_if_compiling_contained_td = False includes_tool_dependencies = False includes_tools_for_display_in_tool_panel = False ctx = suc.get_changectx_for_changeset( repo, changeset_revision ) @@ -259,7 +260,8 @@ repository_metadata=repository_metadata, tool_dependencies=None, repository_dependencies=None ) - return repo_info_dict, includes_tools, includes_tool_dependencies, includes_tools_for_display_in_tool_panel, has_repository_dependencies + return repo_info_dict, includes_tools, includes_tool_dependencies, includes_tools_for_display_in_tool_panel, \ + has_repository_dependencies, has_repository_dependencies_only_if_compiling_contained_td def get_repository_components_for_installation( encoded_tsr_id, encoded_tsr_ids, repo_info_dicts, tool_panel_section_keys ): """ @@ -311,6 +313,7 @@ includes_tool_dependencies = update_dict.get( 'includes_tool_dependencies', False ) includes_workflows = update_dict.get( 'includes_workflows', False ) has_repository_dependencies = update_dict.get( 'has_repository_dependencies', False ) + has_repository_dependencies_only_if_compiling_contained_td = update_dict.get( 'has_repository_dependencies_only_if_compiling_contained_td', False ) changeset_revision = update_dict.get( 'changeset_revision', None ) ctx_rev = update_dict.get( 'ctx_rev', None ) changeset_revision_dict[ 'includes_data_managers' ] = includes_data_managers @@ -320,6 +323,7 @@ changeset_revision_dict[ 'includes_tool_dependencies' ] = includes_tool_dependencies changeset_revision_dict[ 'includes_workflows' ] = includes_workflows changeset_revision_dict[ 'has_repository_dependencies' ] = has_repository_dependencies + changeset_revision_dict[ 'has_repository_dependencies_only_if_compiling_contained_td' ] = has_repository_dependencies_only_if_compiling_contained_td changeset_revision_dict[ 'changeset_revision' ] = changeset_revision changeset_revision_dict[ 'ctx_rev' ] = ctx_rev except Exception, e: @@ -331,6 +335,7 @@ changeset_revision_dict[ 'includes_tool_dependencies' ] = False changeset_revision_dict[ 'includes_workflows' ] = False changeset_revision_dict[ 'has_repository_dependencies' ] = False + changeset_revision_dict[ 'has_repository_dependencies_only_if_compiling_contained_td' ] = False changeset_revision_dict[ 'changeset_revision' ] = None changeset_revision_dict[ 'ctx_rev' ] = None return changeset_revision_dict diff -r 93215e7e74d020b478803ce2755f76c7e5236f16 -r ab20415126a768f456314cfe587e4ce71fd2049b lib/tool_shed/galaxy_install/tool_dependencies/install_util.py --- a/lib/tool_shed/galaxy_install/tool_dependencies/install_util.py +++ b/lib/tool_shed/galaxy_install/tool_dependencies/install_util.py @@ -394,7 +394,7 @@ if not binary_installed: print 'Binary installation did not occur, so proceeding with install and compile recipe.' # Make sure to reset for installation if attempt at binary installation resulted in an error. - if tool_dependency.status != app.model.ToolDependency.installation_status.NEW: + if tool_dependency.status != app.model.ToolDependency.installation_status.NEVER_INSTALLED: removed, error_message = tool_dependency_util.remove_tool_dependency( app, tool_dependency ) install_via_fabric( app, tool_dependency, diff -r 93215e7e74d020b478803ce2755f76c7e5236f16 -r ab20415126a768f456314cfe587e4ce71fd2049b lib/tool_shed/util/common_install_util.py --- a/lib/tool_shed/util/common_install_util.py +++ b/lib/tool_shed/util/common_install_util.py @@ -12,6 +12,7 @@ from tool_shed.util import encoding_util from tool_shed.util import data_manager_util from tool_shed.util import datatype_util +from tool_shed.util import tool_dependency_util from tool_shed.util import tool_util from tool_shed.util import xml_util from tool_shed.galaxy_install.tool_dependencies.install_util import install_package @@ -69,16 +70,28 @@ Return dictionaries containing the sets of installed and missing tool dependencies and repository dependencies associated with the repository defined by the received repo_info_dict. """ + repository = None + installed_rd = {} + installed_td = {} + missing_rd = {} + missing_td = {} name = repo_info_dict.keys()[ 0 ] repo_info_tuple = repo_info_dict[ name ] - description, repository_clone_url, changeset_revision, ctx_rev, repository_owner, repository_dependencies, installed_td = \ + description, repository_clone_url, changeset_revision, ctx_rev, repository_owner, repository_dependencies, tool_dependencies = \ suc.get_repo_info_tuple_contents( repo_info_tuple ) + if tool_dependencies: + if not includes_tool_dependencies: + includes_tool_dependencies = True + # Inspect the tool_dependencies dictionary to separate the installed and missing tool dependencies. We don't add to installed_td + # and missing_td here because at this point they are empty. + installed_td, missing_td = get_installed_and_missing_tool_dependencies( trans, tool_shed_url, tool_dependencies ) + # In cases where a repository dependency is required only for compiling a dependent repository's tool dependency, the value of + # repository_dependencies will be an empty dictionary here. if repository_dependencies: # We have a repository with one or more defined repository dependencies. missing_td = {} - # Handle the scenario where a repository was installed, then uninstalled and an error occurred during the re-installation process. - # In this case, a record for the repository will exist in the database with the status of 'New'. - repository = suc.get_repository_for_dependency_relationship( trans.app, tool_shed_url, name, repository_owner, changeset_revision ) + if not repository: + repository = suc.get_repository_for_dependency_relationship( trans.app, tool_shed_url, name, repository_owner, changeset_revision ) if repository and repository.metadata: installed_rd, missing_rd = get_installed_and_missing_repository_dependencies( trans, repository ) else: @@ -86,73 +99,70 @@ # Discover all repository dependencies and retrieve information for installing them. all_repo_info_dict = get_required_repo_info_dicts( trans, tool_shed_url, util.listify( repo_info_dict ) ) has_repository_dependencies = all_repo_info_dict.get( 'has_repository_dependencies', False ) + has_repository_dependencies_only_if_compiling_contained_td = all_repo_info_dict.get( 'has_repository_dependencies_only_if_compiling_contained_td', False ) includes_tools_for_display_in_tool_panel = all_repo_info_dict.get( 'includes_tools_for_display_in_tool_panel', False ) includes_tool_dependencies = all_repo_info_dict.get( 'includes_tool_dependencies', False ) includes_tools = all_repo_info_dict.get( 'includes_tools', False ) required_repo_info_dicts = all_repo_info_dict.get( 'all_repo_info_dicts', [] ) # Display tool dependencies defined for each of the repository dependencies. if required_repo_info_dicts: - all_tool_dependencies = {} + required_tool_dependencies = {} for rid in required_repo_info_dicts: for name, repo_info_tuple in rid.items(): - description, repository_clone_url, changeset_revision, ctx_rev, repository_owner, repository_dependencies, rid_installed_td = \ + description, repository_clone_url, changeset_revision, ctx_rev, repository_owner, rid_repository_dependencies, rid_tool_dependencies = \ suc.get_repo_info_tuple_contents( repo_info_tuple ) - if rid_installed_td: - for td_key, td_dict in rid_installed_td.items(): - if td_key not in all_tool_dependencies: - all_tool_dependencies[ td_key ] = td_dict - if all_tool_dependencies: - if installed_td is None: - installed_td = {} - else: - # Move all tool dependencies to the missing_tool_dependencies container. - for td_key, td_dict in installed_td.items(): - if td_key not in missing_td: - missing_td[ td_key ] = td_dict - installed_td = {} + if rid_tool_dependencies: + for td_key, td_dict in rid_tool_dependencies.items(): + if td_key not in required_tool_dependencies: + required_tool_dependencies[ td_key ] = td_dict + if required_tool_dependencies: # Discover and categorize all tool dependencies defined for this repository's repository dependencies. - required_tool_dependencies, required_missing_tool_dependencies = \ - get_installed_and_missing_tool_dependencies_for_new_install( trans, all_tool_dependencies ) - if required_tool_dependencies: + required_installed_td, required_missing_td = get_installed_and_missing_tool_dependencies( trans, + tool_shed_url, + required_tool_dependencies ) + if required_installed_td: if not includes_tool_dependencies: includes_tool_dependencies = True - for td_key, td_dict in required_tool_dependencies.items(): + for td_key, td_dict in required_installed_td.items(): if td_key not in installed_td: installed_td[ td_key ] = td_dict - if required_missing_tool_dependencies: + if required_missing_td: if not includes_tool_dependencies: includes_tool_dependencies = True - for td_key, td_dict in required_missing_tool_dependencies.items(): + for td_key, td_dict in required_missing_td.items(): if td_key not in missing_td: missing_td[ td_key ] = td_dict else: - # We have a single repository with no defined repository dependencies. + # We have a single repository with (possibly) no defined repository dependencies. all_repo_info_dict = get_required_repo_info_dicts( trans, tool_shed_url, util.listify( repo_info_dict ) ) has_repository_dependencies = all_repo_info_dict.get( 'has_repository_dependencies', False ) + has_repository_dependencies_only_if_compiling_contained_td = all_repo_info_dict.get( 'has_repository_dependencies_only_if_compiling_contained_td', False ) includes_tools_for_display_in_tool_panel = all_repo_info_dict.get( 'includes_tools_for_display_in_tool_panel', False ) includes_tool_dependencies = all_repo_info_dict.get( 'includes_tool_dependencies', False ) includes_tools = all_repo_info_dict.get( 'includes_tools', False ) required_repo_info_dicts = all_repo_info_dict.get( 'all_repo_info_dicts', [] ) - installed_rd = None - missing_rd = None - missing_td = None - dependencies_for_repository_dict = dict( changeset_revision=changeset_revision, - has_repository_dependencies=has_repository_dependencies, - includes_tool_dependencies=includes_tool_dependencies, - includes_tools=includes_tools, - includes_tools_for_display_in_tool_panel=includes_tools_for_display_in_tool_panel, - installed_repository_dependencies=installed_rd, - installed_tool_dependencies=installed_td, - missing_repository_dependencies=missing_rd, - missing_tool_dependencies=missing_td, - name=name, - repository_owner=repository_owner ) + dependencies_for_repository_dict = \ + dict( changeset_revision=changeset_revision, + has_repository_dependencies=has_repository_dependencies, + has_repository_dependencies_only_if_compiling_contained_td=has_repository_dependencies_only_if_compiling_contained_td, + includes_tool_dependencies=includes_tool_dependencies, + includes_tools=includes_tools, + includes_tools_for_display_in_tool_panel=includes_tools_for_display_in_tool_panel, + installed_repository_dependencies=installed_rd, + installed_tool_dependencies=installed_td, + missing_repository_dependencies=missing_rd, + missing_tool_dependencies=missing_td, + name=name, + repository_owner=repository_owner ) return dependencies_for_repository_dict def get_installed_and_missing_repository_dependencies( trans, repository ): """ Return the installed and missing repository dependencies for a tool shed repository that has a record in the Galaxy database, but - may or may not be installed. In this case, the repository dependencies are associated with the repository in the database. + may or may not be installed. In this case, the repository dependencies are associated with the repository in the database. Do not + include a repository dependency if it is required only to compile a tool dependency defined for the dependent repository since these + special kinds of repository dependencies are really a dependency of the dependent repository's contained tool dependency, and only if + that tool dependency requires compilation. """ missing_repository_dependencies = {} installed_repository_dependencies = {} @@ -166,7 +176,14 @@ for tsr in repository.repository_dependencies: prior_installation_required = suc.set_prior_installation_required( repository, tsr ) only_if_compiling_contained_td = suc.set_only_if_compiling_contained_td( repository, tsr ) - rd_tup = [ tsr.tool_shed, tsr.name, tsr.owner, tsr.changeset_revision, prior_installation_required, only_if_compiling_contained_td, tsr.id, tsr.status ] + rd_tup = [ tsr.tool_shed, + tsr.name, + tsr.owner, + tsr.changeset_revision, + prior_installation_required, + only_if_compiling_contained_td, + tsr.id, + tsr.status ] if tsr.status == trans.model.ToolShedRepository.installation_status.INSTALLED: installed_rd_tups.append( rd_tup ) else: @@ -184,7 +201,7 @@ repository_dependencies = metadata.get( 'repository_dependencies', {} ) description = repository_dependencies.get( 'description', None ) # We need to add a root_key entry to one or both of installed_repository_dependencies dictionary and the missing_repository_dependencies - # dictionary for proper display parsing. + # dictionaries for proper display parsing. root_key = container_util.generate_repository_dependencies_key_for_repository( repository.tool_shed, repository.name, repository.owner, @@ -210,7 +227,7 @@ installed_repository_dependencies = {} missing_rd_tups = [] installed_rd_tups = [] - description, repository_clone_url, changeset_revision, ctx_rev, repository_owner, repository_dependencies, installed_td = \ + description, repository_clone_url, changeset_revision, ctx_rev, repository_owner, repository_dependencies, tool_dependencies = \ suc.get_repo_info_tuple_contents( repo_info_tuple ) if repository_dependencies: description = repository_dependencies[ 'description' ] @@ -228,7 +245,7 @@ # tuple looks like: ( description, repository_clone_url, changeset_revision, ctx_rev, repository_owner, repository_dependencies, installed_td ) tmp_clone_url = suc.generate_clone_url_from_repo_info_tup( rd_tup ) tmp_repo_info_tuple = ( None, tmp_clone_url, changeset_revision, None, owner, None, None ) - repository, current_changeset_revision = suc.repository_was_previously_installed( trans, tool_shed, name, tmp_repo_info_tuple ) + repository, installed_changeset_revision = suc.repository_was_previously_installed( trans, tool_shed, name, tmp_repo_info_tuple ) if repository: new_rd_tup = [ tool_shed, name, @@ -273,29 +290,46 @@ missing_repository_dependencies[ 'description' ] = description return installed_repository_dependencies, missing_repository_dependencies -def get_installed_and_missing_tool_dependencies_for_new_install( trans, all_tool_dependencies ): +def get_installed_and_missing_tool_dependencies( trans, tool_shed_url, tool_dependencies_dict ): """Return the lists of installed tool dependencies and missing tool dependencies for a set of repositories being installed into Galaxy.""" - # FIXME: confirm that this method currently populates and returns only missing tool dependencies. If so, this method should be enhanced to search for - # installed tool dependencies defined as complex repository dependency relationships. - if all_tool_dependencies: - tool_dependencies = {} - missing_tool_dependencies = {} - for td_key, val in all_tool_dependencies.items(): - # Set environment tool dependencies are a list, set each member to never installed. + installed_tool_dependencies = {} + missing_tool_dependencies = {} + if tool_dependencies_dict: + for td_key, val in tool_dependencies_dict.items(): + # Default the status to NEVER_INSTALLED. + tool_dependency_status = trans.model.ToolDependency.installation_status.NEVER_INSTALLED + # Set environment tool dependencies are a list. if td_key == 'set_environment': new_val = [] for requirement_dict in val: - requirement_dict[ 'status' ] = trans.model.ToolDependency.installation_status.NEVER_INSTALLED + # {'repository_name': 'xx', 'name': 'bwa', 'version': '0.5.9', 'repository_owner': 'yy', 'changeset_revision': 'zz', 'type': 'package'} + tool_dependency = tool_dependency_util.get_tool_dependency_by_name_version_type( trans.app, + requirement_dict.get( 'name', None ), + requirement_dict.get( 'version', None ), + requirement_dict.get( 'type', 'package' ) ) + if tool_dependency: + tool_dependency_status = tool_dependency.status + requirement_dict[ 'status' ] = tool_dependency_status new_val.append( requirement_dict ) - missing_tool_dependencies[ td_key ] = new_val + if tool_dependency_status in [ trans.model.ToolDependency.installation_status.INSTALLED ]: + installed_tool_dependencies[ td_key ] = new_val + else: + missing_tool_dependencies[ td_key ] = new_val else: - # Since we have a new install, missing tool dependencies have never been installed. - val[ 'status' ] = trans.model.ToolDependency.installation_status.NEVER_INSTALLED + # The val dictionary looks something like this: + # {'repository_name': 'xx', 'name': 'bwa', 'version': '0.5.9', 'repository_owner': 'yy', 'changeset_revision': 'zz', 'type': 'package'} + tool_dependency = tool_dependency_util.get_tool_dependency_by_name_version_type( trans.app, + val.get( 'name', None ), + val.get( 'version', None ), + val.get( 'type', 'package' ) ) + if tool_dependency: + tool_dependency_status = tool_dependency.status + val[ 'status' ] = tool_dependency_status + if tool_dependency_status in [ trans.model.ToolDependency.installation_status.INSTALLED ]: + installed_tool_dependencies[ td_key ] = val + else: missing_tool_dependencies[ td_key ] = val - else: - tool_dependencies = None - missing_tool_dependencies = None - return tool_dependencies, missing_tool_dependencies + return installed_tool_dependencies, missing_tool_dependencies def get_required_repo_info_dicts( trans, tool_shed_url, repo_info_dicts ): """ @@ -328,7 +362,9 @@ toolshed, name, owner, changeset_revision = container_util.get_components_from_key( key ) components_list = [ toolshed, name, owner, changeset_revision ] only_if_compiling_contained_td = 'False' - # Skip listing a repository dependency if it is required only to compile a tool dependency defined for the dependent repository. + # Skip listing a repository dependency if it is required only to compile a tool dependency defined for the dependent repository since + # in this case, the repository dependency is really a dependency of the dependent repository's contained tool dependency, and only if + # that tool dependency requires compilation. if not util.asbool( only_if_compiling_contained_td ): if components_list not in required_repository_tups: required_repository_tups.append( components_list ) @@ -337,8 +373,8 @@ only_if_compiling_contained_td = components_list[ 5 ] except: only_if_compiling_contained_td = 'False' - # TODO: Fix this to display the tool dependency if only_if_compiling_contained_td is True, but clarify that installation may not - # happen. + # Skip listing a repository dependency if it is required only to compile a tool dependency defined for the dependent repository + # (see above comment). if not util.asbool( only_if_compiling_contained_td ): if components_list not in required_repository_tups: required_repository_tups.append( components_list ) diff -r 93215e7e74d020b478803ce2755f76c7e5236f16 -r ab20415126a768f456314cfe587e4ce71fd2049b lib/tool_shed/util/common_util.py --- a/lib/tool_shed/util/common_util.py +++ b/lib/tool_shed/util/common_util.py @@ -1,3 +1,4 @@ +import logging import os import urllib2 from galaxy.util import json @@ -5,6 +6,8 @@ from tool_shed.util import encoding_util from tool_shed.util import xml_util +log = logging.getLogger( __name__ ) + REPOSITORY_OWNER = 'devteam' def accumulate_tool_dependencies( tool_shed_accessible, tool_dependencies, all_tool_dependencies ): diff -r 93215e7e74d020b478803ce2755f76c7e5236f16 -r ab20415126a768f456314cfe587e4ce71fd2049b lib/tool_shed/util/metadata_util.py --- a/lib/tool_shed/util/metadata_util.py +++ b/lib/tool_shed/util/metadata_util.py @@ -280,13 +280,16 @@ def create_or_update_repository_metadata( trans, id, repository, changeset_revision, metadata_dict ): """Create or update a repository_metadatqa record in the tool shed.""" has_repository_dependencies = False + has_repository_dependencies_only_if_compiling_contained_td = False includes_datatypes = False includes_tools = False includes_tool_dependencies = False includes_workflows = False if metadata_dict: - if 'repository_dependencies' in metadata_dict: - has_repository_dependencies = True + repository_dependencies_dict = metadata_dict.get( 'repository_dependencies', {} ) + repository_dependencies = repository_dependencies_dict.get( 'repository_dependencies', [] ) + has_repository_dependencies, has_repository_dependencies_only_if_compiling_contained_td = \ + suc.get_repository_dependency_types( repository_dependencies ) if 'datatypes' in metadata_dict: includes_datatypes = True if 'tools' in metadata_dict: @@ -295,7 +298,11 @@ includes_tool_dependencies = True if 'workflows' in metadata_dict: includes_workflows = True - downloadable = has_repository_dependencies or includes_datatypes or includes_tools or includes_tool_dependencies or includes_workflows + if has_repository_dependencies or has_repository_dependencies_only_if_compiling_contained_td or includes_datatypes or \ + includes_tools or includes_tool_dependencies or includes_workflows: + downloadable = True + else: + downloadable = False repository_metadata = suc.get_repository_metadata_by_changeset_revision( trans, id, changeset_revision ) if repository_metadata: # A repository metadata record already exists with the received changeset_revision, so we don't need to check the skip_tool_test table. @@ -1851,10 +1858,13 @@ repository_metadata.includes_datatypes = True else: repository_metadata.includes_datatypes = False - if 'repository_dependencies' in metadata_dict: - repository_metadata.has_repository_dependencies = True - else: - repository_metadata.has_repository_dependencies = False + # We don't store information about the special type of repository dependency that is needed only for compiling a tool dependency + # defined for the dependent repository. + repository_dependencies_dict = metadata_dict.get( 'repository_dependencies', {} ) + repository_dependencies = repository_dependencies_dict.get( 'repository_dependencies', [] ) + has_repository_dependencies, has_repository_dependencies_only_if_compiling_contained_td = \ + suc.get_repository_dependency_types( repository_dependencies ) + repository_metadata.has_repository_dependencies = has_repository_dependencies if 'tool_dependencies' in metadata_dict: repository_metadata.includes_tool_dependencies = True else: diff -r 93215e7e74d020b478803ce2755f76c7e5236f16 -r ab20415126a768f456314cfe587e4ce71fd2049b lib/tool_shed/util/repository_dependency_util.py --- a/lib/tool_shed/util/repository_dependency_util.py +++ b/lib/tool_shed/util/repository_dependency_util.py @@ -139,6 +139,7 @@ # repository dependencies are not to be installed, only those items contained in the received repo_info_dicts list will be processed. if is_in_repo_info_dicts( repo_info_dict, repo_info_dicts ) or install_repository_dependencies: if installed_tool_shed_repository.status in [ trans.model.ToolShedRepository.installation_status.ERROR, + trans.model.ToolShedRepository.installation_status.NEW, trans.model.ToolShedRepository.installation_status.UNINSTALLED ]: # The current tool shed repository is not currently installed, so we can update it's record in the database. can_update = True diff -r 93215e7e74d020b478803ce2755f76c7e5236f16 -r ab20415126a768f456314cfe587e4ce71fd2049b lib/tool_shed/util/shed_util_common.py --- a/lib/tool_shed/util/shed_util_common.py +++ b/lib/tool_shed/util/shed_util_common.py @@ -868,6 +868,31 @@ .first() return None +def get_repository_dependency_types( repository_dependencies ): + """ + Inspect the received list of repository_dependencies tuples and return boolean values for has_repository_dependencies and + has_repository_dependencies_only_if_compiling_contained_td. + """ + # Set has_repository_dependencies, which will be True only if at least one repository_dependency is defined with the value of + # only_if_compiling_contained_td as False. + has_repository_dependencies = False + for rd_tup in repository_dependencies: + tool_shed, name, owner, changeset_revision, prior_installation_required, only_if_compiling_contained_td = \ + common_util.parse_repository_dependency_tuple( rd_tup ) + if not asbool( only_if_compiling_contained_td ): + has_repository_dependencies = True + break + # Set has_repository_dependencies_only_if_compiling_contained_td, which will be True only if at least one repository_dependency is + # defined with the value of only_if_compiling_contained_td as True. + has_repository_dependencies_only_if_compiling_contained_td = False + for rd_tup in repository_dependencies: + tool_shed, name, owner, changeset_revision, prior_installation_required, only_if_compiling_contained_td = \ + common_util.parse_repository_dependency_tuple( rd_tup ) + if asbool( only_if_compiling_contained_td ): + has_repository_dependencies_only_if_compiling_contained_td = True + break + return has_repository_dependencies, has_repository_dependencies_only_if_compiling_contained_td + def get_repository_for_dependency_relationship( app, tool_shed, name, owner, changeset_revision ): """Return an installed tool_shed_repository database record that is defined by either the current changeset revision or the installed_changeset_revision.""" # This method is used only in Galaxy, not the tool shed. @@ -1389,14 +1414,23 @@ def repository_was_previously_installed( trans, tool_shed_url, repository_name, repo_info_tuple ): """ - Handle the case where the repository was previously installed using an older changeset_revsion, but later the repository was updated - in the tool shed and now we're trying to install the latest changeset revision of the same repository instead of updating the one - that was previously installed. We'll look in the database instead of on disk since the repository may be uninstalled. + Find out if a repository is already installed into Galaxy - there are several scenarios where this is necessary. For example, this method + will handle the case where the repository was previously installed using an older changeset_revsion, but later the repository was updated + in the tool shed and now we're trying to install the latest changeset revision of the same repository instead of updating the one that was + previously installed. We'll look in the database instead of on disk since the repository may be currently uninstalled. """ description, repository_clone_url, changeset_revision, ctx_rev, repository_owner, repository_dependencies, tool_dependencies = \ get_repo_info_tuple_contents( repo_info_tuple ) tool_shed = get_tool_shed_from_clone_url( repository_clone_url ) - # Get all previous change set revisions from the tool shed for the repository back to, but excluding, the previous valid changeset + # See if we can locate the repository using the value of changeset_revision. + tool_shed_repository = get_tool_shed_repository_by_shed_name_owner_installed_changeset_revision( trans.app, + tool_shed, + repository_name, + repository_owner, + changeset_revision ) + if tool_shed_repository: + return tool_shed_repository, changeset_revision + # Get all previous changeset revisions from the tool shed for the repository back to, but excluding, the previous valid changeset # revision to see if it was previously installed using one of them. url = url_join( tool_shed_url, 'repository/previous_changeset_revisions?galaxy_url=%s&name=%s&owner=%s&changeset_revision=%s' % \ @@ -1410,14 +1444,14 @@ repository_name, repository_owner, previous_changeset_revision ) - if tool_shed_repository and tool_shed_repository.status not in [ trans.model.ToolShedRepository.installation_status.NEW ]: + if tool_shed_repository: return tool_shed_repository, previous_changeset_revision return None, None def reset_previously_installed_repository( trans, repository ): """ Reset the atrributes of a tool_shed_repository that was previsouly installed. The repository will be in some state other than with a - status of INSTALLED, so all atributes will be set to the default (NEW( state. This will enable the repository to be freshly installed. + status of INSTALLED, so all atributes will be set to the default NEW state. This will enable the repository to be freshly installed. """ repository.deleted = False repository.tool_shed_status = None diff -r 93215e7e74d020b478803ce2755f76c7e5236f16 -r ab20415126a768f456314cfe587e4ce71fd2049b lib/tool_shed/util/tool_dependency_util.py --- a/lib/tool_shed/util/tool_dependency_util.py +++ b/lib/tool_shed/util/tool_dependency_util.py @@ -258,6 +258,14 @@ app.model.ToolDependency.table.c.type == type ) ) \ .first() +def get_tool_dependency_by_name_version_type( app, name, version, type ): + sa_session = app.model.context.current + return sa_session.query( app.model.ToolDependency ) \ + .filter( and_( app.model.ToolDependency.table.c.name == name, + app.model.ToolDependency.table.c.version == version, + app.model.ToolDependency.table.c.type == type ) ) \ + .first() + def get_tool_dependency_by_name_version_type_repository( app, repository, name, version, type ): sa_session = app.model.context.current return sa_session.query( app.model.ToolDependency ) \ diff -r 93215e7e74d020b478803ce2755f76c7e5236f16 -r ab20415126a768f456314cfe587e4ce71fd2049b lib/tool_shed/util/tool_util.py --- a/lib/tool_shed/util/tool_util.py +++ b/lib/tool_shed/util/tool_util.py @@ -962,7 +962,7 @@ suc.config_elems_to_xml_file( trans.app, config_elems, shed_tool_conf, tool_path ) def remove_from_tool_panel( trans, repository, shed_tool_conf, uninstall ): - """A tool shed repository is being deactivated or uninstalled so handle tool panel alterations accordingly.""" + """A tool shed repository is being deactivated or uninstalled, so handle tool panel alterations accordingly.""" # Determine where the tools are currently defined in the tool panel and store this information so the tools can be displayed # in the same way when the repository is activated or reinstalled. tool_panel_dict = suc.generate_tool_panel_dict_from_shed_tool_conf_entries( trans.app, repository ) diff -r 93215e7e74d020b478803ce2755f76c7e5236f16 -r ab20415126a768f456314cfe587e4ce71fd2049b test/tool_shed/base/twilltestcase.py --- a/test/tool_shed/base/twilltestcase.py +++ b/test/tool_shed/base/twilltestcase.py @@ -114,7 +114,7 @@ # version=section_version ) # This dict is appended to tool_panel_section_metadata[ tool_guid ] tool_panel_section = tool_panel_section_metadata[ tool_guid ][ 0 ][ 'name' ] - assert tool_panel_section == expected_tool_panel_section, 'Expected tool panel section %s, found %s\nMetadata: %s\n' % \ + assert tool_panel_section == expected_tool_panel_section, 'Expected to find tool panel section *%s*, but instead found *%s*\nMetadata: %s\n' % \ ( expected_tool_panel_section, tool_panel_section, metadata ) def check_installed_repository_tool_dependencies( self, 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.