diff --git a/lib/galaxy/web/form_builder.py b/lib/galaxy/web/form_builder.py index 7cab4188cdd..fbdaf72fc11 100644 --- a/lib/galaxy/web/form_builder.py +++ b/lib/galaxy/web/form_builder.py @@ -288,8 +288,9 @@ class SelectField(BaseField):
""" - def __init__( self, name, multiple=None, display=None, refresh_on_change=False, refresh_on_change_values=None, size=None ): + def __init__( self, name, multiple=None, display=None, refresh_on_change=False, refresh_on_change_values=None, size=None, field_id=None ): self.name = name + self.field_id = field_id self.multiple = multiple or False self.size = size self.options = list() @@ -312,7 +313,11 @@ class SelectField(BaseField): def add_option( self, text, value, selected=False ): self.options.append( ( text, value, selected ) ) - def get_html( self, prefix="", disabled=False ): + def get_html( self, prefix="", disabled=False, extra_attr=None ): + if extra_attr is not None: + self.extra_attributes = ' %s' % ' '.join( [ '%s="%s"' % ( k, escape( v ) ) for k, v in extra_attr.items() ] ) + else: + self.extra_attributes = '' if self.display == "checkboxes": return self.get_html_checkboxes( prefix, disabled ) elif self.display == "radio": @@ -335,8 +340,8 @@ class SelectField(BaseField): selected_text = "" if selected: selected_text = " checked='checked'" - rval.append( '' - % ( style, prefix, self.name, escaped_value, uniq_id, selected_text, self.get_disabled_str( disabled ), uniq_id, escape( text, quote=True ) ) ) + rval.append( '' + % ( style, prefix, self.name, escaped_value, uniq_id, selected_text, self.get_disabled_str( disabled ), self.extra_attributes, uniq_id, escape( text, quote=True ) ) ) ctr += 1 return unicodify( "\n".join( rval ) ) @@ -352,7 +357,7 @@ class SelectField(BaseField): selected_text = "" if selected: selected_text = " checked='checked'" - rval.append( '' + rval.append( '' % ( style, prefix, self.name, @@ -361,6 +366,7 @@ class SelectField(BaseField): uniq_id, selected_text, self.get_disabled_str( disabled ), + self.extra_attributes, uniq_id, text ) ) ctr += 1 @@ -388,8 +394,12 @@ class SelectField(BaseField): rval.append( '' % ( escape( unicodify( value ), quote=True ), selected_text, escape( unicodify( text ), quote=True ) ) ) if last_selected_value: last_selected_value = ' last_selected_value="%s"' % escape( unicodify( last_selected_value ), quote=True ) - rval.insert( 0, '' + % ( prefix, self.name, multiple, size, self.refresh_on_change_text, last_selected_value, self.get_disabled_str( disabled ), id_string, self.extra_attributes ) ) rval.append( '' ) return unicodify( "\n".join( rval ) ) diff --git a/lib/galaxy/webapps/tool_shed/api/categories.py b/lib/galaxy/webapps/tool_shed/api/categories.py index 0083ee49bb7..1fc1b0f2fe1 100644 --- a/lib/galaxy/webapps/tool_shed/api/categories.py +++ b/lib/galaxy/webapps/tool_shed/api/categories.py @@ -15,8 +15,11 @@ log = logging.getLogger( __name__ ) class CategoriesController( BaseAPIController ): """RESTful controller for interactions with categories in the Tool Shed.""" + def __get_repository_count( self, trans, category_name ): + return self.app.repository_registry.viewable_repositories_and_suites_by_category.get( category_name, 0 ) + def __get_value_mapper( self, trans ): - value_mapper = { 'id' : trans.security.encode_id } + value_mapper = { 'id': trans.security.encode_id } return value_mapper @expose_api @@ -41,11 +44,11 @@ class CategoriesController( BaseAPIController ): if not description: # Default the description to the name. description = name - if suc.get_category_by_name( trans.app, name ): + if suc.get_category_by_name( self.app, name ): raise exceptions.Conflict( 'A category with that name already exists.' ) else: # Create the category - category = trans.app.model.Category( name=name, description=description ) + category = self.app.model.Category( name=name, description=description ) trans.sa_session.add( category ) trans.sa_session.flush() category_dict = category.to_dict( view='element', @@ -58,6 +61,30 @@ class CategoriesController( BaseAPIController ): raise exceptions.RequestParameterMissingException( 'Missing required parameter "name".' ) return category_dict + @expose_api_anonymous_and_sessionless + def get_repositories( self, trans, category_id, **kwd ): + """ + GET /api/categories/{encoded_category_id}/repositories + Return information about the provided category and the repositories in that category. + + :param id: the encoded id of the Category object + + Example: GET localhost:9009/api/categories/f9cad7b01a472135/repositories + """ + category = suc.get_category( self.app, category_id ) + if category is None: + category_dict = dict( message='Unable to locate category record for id %s.' % ( str( id ) ), + status='error' ) + return category_dict + category_dict = category.to_dict( view='element', + value_mapper=self.__get_value_mapper( trans ) ) + category_dict[ 'url' ] = web.url_for( controller='categories', + action='show', + id=trans.security.encode_id( category.id ) ) + repositories = suc.get_repositories_by_category( self.app, category.id ) + category_dict[ 'repositories' ] = repositories + return category_dict + @expose_api_anonymous_and_sessionless def index( self, trans, deleted=False, **kwd ): """ @@ -72,14 +99,15 @@ class CategoriesController( BaseAPIController ): deleted = util.asbool( deleted ) if deleted and not trans.user_is_admin(): raise exceptions.AdminRequiredException( 'Only administrators can query deleted categories.' ) - for category in trans.sa_session.query( trans.app.model.Category ) \ - .filter( trans.app.model.Category.table.c.deleted == deleted ) \ - .order_by( trans.app.model.Category.table.c.name ): + for category in trans.sa_session.query( self.app.model.Category ) \ + .filter( self.app.model.Category.table.c.deleted == deleted ) \ + .order_by( self.app.model.Category.table.c.name ): category_dict = category.to_dict( view='collection', value_mapper=self.__get_value_mapper( trans ) ) category_dict[ 'url' ] = web.url_for( controller='categories', action='show', id=trans.security.encode_id( category.id ) ) + category_dict[ 'repositories' ] = self.app.repository_registry.viewable_repositories_and_suites_by_category.get( category.name, 0 ) category_dicts.append( category_dict ) return category_dicts @@ -93,7 +121,7 @@ class CategoriesController( BaseAPIController ): Example: GET localhost:9009/api/categories/f9cad7b01a472135 """ - category = suc.get_category( trans.app, id ) + category = suc.get_category( self.app, id ) if category is None: category_dict = dict( message='Unable to locate category record for id %s.' % ( str( id ) ), status='error' ) diff --git a/lib/galaxy/webapps/tool_shed/api/repositories.py b/lib/galaxy/webapps/tool_shed/api/repositories.py index 0eede27d663..73dd2d0dcd0 100644 --- a/lib/galaxy/webapps/tool_shed/api/repositories.py +++ b/lib/galaxy/webapps/tool_shed/api/repositories.py @@ -73,7 +73,7 @@ class RepositoriesController( BaseAPIController ): owner = payload.get( 'owner', '' ) if not owner: raise HTTPBadRequest( detail="Missing required parameter 'owner'." ) - repository = suc.get_repository_by_name_and_owner( trans.app, name, owner ) + repository = suc.get_repository_by_name_and_owner( self.app, name, owner ) if repository is None: error_message = 'Cannot locate repository with name %s and owner %s,' % ( str( name ), str( owner ) ) log.debug( error_message ) @@ -81,14 +81,14 @@ class RepositoriesController( BaseAPIController ): response_dict[ 'message' ] = error_message return response_dict # Update the repository registry. - trans.app.repository_registry.add_entry( repository ) + self.app.repository_registry.add_entry( repository ) response_dict[ 'status' ] = 'ok' response_dict[ 'message' ] = 'Entries for repository %s owned by %s have been added to the Tool Shed repository registry.' \ % ( name, owner ) return response_dict @web.expose_api_anonymous - def get_ordered_installable_revisions( self, trans, name, owner, **kwd ): + def get_ordered_installable_revisions( self, trans, **kwd ): """ GET /api/repositories/get_ordered_installable_revisions @@ -98,23 +98,21 @@ class RepositoriesController( BaseAPIController ): Returns the ordered list of changeset revision hash strings that are associated with installable revisions. As in the changelog, the list is ordered oldest to newest. """ - # Example URL: http://localhost:9009/api/repositories/get_installable_revisions?name=add_column&owner=test - if name and owner: + # Example URL: http://localhost:9009/api/repositories/get_ordered_installable_revisions?name=add_column&owner=test + name = kwd.get( 'name', None ) + owner = kwd.get( 'owner', None ) + tsr_id = kwd.get( 'tsr_id', None ) + if None not in [ name, owner ]: # Get the repository information. - repository = suc.get_repository_by_name_and_owner( trans.app, name, owner ) - if repository is None: - error_message = "Error in the Tool Shed repositories API in get_ordered_installable_revisions: " - error_message += "cannot locate repository %s owned by %s." % ( str( name ), str( owner ) ) - log.debug( error_message ) - return [] - repo = hg_util.get_repo_for_repository( trans.app, repository=repository, repo_path=None, create=False ) - ordered_installable_revisions = suc.get_ordered_metadata_changeset_revisions( repository, repo, downloadable=True ) - return ordered_installable_revisions + repository = suc.get_repository_by_name_and_owner( self.app, name, owner ) + elif tsr_id is not None: + repository = suc.get_repository_in_tool_shed( self.app, tsr_id ) else: error_message = "Error in the Tool Shed repositories API in get_ordered_installable_revisions: " - error_message += "invalid name %s or owner %s received." % ( str( name ), str( owner ) ) + error_message += "invalid parameters received." % ( str( name ), str( owner ) ) log.debug( error_message ) return [] + return repository.ordered_installable_revisions( self.app ) @web.expose_api_anonymous def get_repository_revision_install_info( self, trans, name, owner, changeset_revision, **kwd ): @@ -187,7 +185,7 @@ class RepositoriesController( BaseAPIController ): # http:///api/repositories/get_repository_revision_install_info?name=&owner=&changeset_revision= if name and owner and changeset_revision: # Get the repository information. - repository = suc.get_repository_by_name_and_owner( trans.app, name, owner ) + repository = suc.get_repository_by_name_and_owner( self.app, name, owner ) if repository is None: log.debug( 'Cannot locate repository %s owned by %s' % ( str( name ), str( owner ) ) ) return {}, {}, {} @@ -198,15 +196,15 @@ class RepositoriesController( BaseAPIController ): action='show', id=encoded_repository_id ) # Get the repository_metadata information. - repository_metadata = suc.get_repository_metadata_by_changeset_revision( trans.app, + repository_metadata = suc.get_repository_metadata_by_changeset_revision( self.app, encoded_repository_id, changeset_revision ) if repository_metadata is None: # The changeset_revision column in the repository_metadata table has been updated with a new # value value, so find the changeset_revision to which we need to update. - repo = hg_util.get_repo_for_repository( trans.app, repository=repository, repo_path=None, create=False ) + repo = hg_util.get_repo_for_repository( self.app, repository=repository, repo_path=None, create=False ) new_changeset_revision = suc.get_next_downloadable_changeset_revision( repository, repo, changeset_revision ) - repository_metadata = suc.get_repository_metadata_by_changeset_revision( trans.app, + repository_metadata = suc.get_repository_metadata_by_changeset_revision( self.app, encoded_repository_id, new_changeset_revision ) changeset_revision = new_changeset_revision @@ -226,7 +224,7 @@ class RepositoriesController( BaseAPIController ): 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.app, + repository_util.get_repo_info_dict( self.app, trans.user, encoded_repository_id, changeset_revision ) @@ -242,10 +240,30 @@ class RepositoriesController( BaseAPIController ): log.debug( debug_msg ) return {}, {}, {} + @web.expose_api_anonymous + def get_installable_revisions( self, trans, **kwd ): + """ + GET /api/repositories/get_installable_revisions + + :param tsr_id: the encoded toolshed ID of the repository + + Returns a list of lists of changesets, in the format [ [ 0, fbb391dc803c ], [ 1, 9d9ec4d9c03e ], [ 2, 9b5b20673b89 ], [ 3, e8c99ce51292 ] ]. + """ + # Example URL: http://localhost:9009/api/repositories/get_installable_revisions?tsr_id=9d37e53072ff9fa4 + tsr_id = kwd.get( 'tsr_id', None ) + if tsr_id is not None: + repository = suc.get_repository_in_tool_shed( self.app, tsr_id ) + else: + error_message = "Error in the Tool Shed repositories API in get_ordered_installable_revisions: " + error_message += "missing or invalid parameter received." + log.debug( error_message ) + return [] + return repository.installable_revisions( self.app ) + def __get_value_mapper( self, trans ): - value_mapper = { 'id' : trans.security.encode_id, - 'repository_id' : trans.security.encode_id, - 'user_id' : trans.security.encode_id } + value_mapper = { 'id': trans.security.encode_id, + 'repository_id': trans.security.encode_id, + 'user_id': trans.security.encode_id } return value_mapper @web.expose_api @@ -283,7 +301,7 @@ class RepositoriesController( BaseAPIController ): except tarfile.ReadError, e: log.debug( 'Error opening capsule file %s: %s' % ( str( capsule_file_name ), str( e ) ) ) return {} - irm = capsule_manager.ImportRepositoryManager( trans.app, + irm = capsule_manager.ImportRepositoryManager( self.app, trans.request.host, trans.user, trans.user_is_admin() ) @@ -386,16 +404,16 @@ class RepositoriesController( BaseAPIController ): response = json.dumps( search_results ) return response - clause_list = [ and_( trans.app.model.Repository.table.c.deprecated == false(), - trans.app.model.Repository.table.c.deleted == deleted ) ] + clause_list = [ and_( self.app.model.Repository.table.c.deprecated == false(), + self.app.model.Repository.table.c.deleted == deleted ) ] if owner is not None: - clause_list.append( and_( trans.app.model.User.table.c.username == owner, - trans.app.model.Repository.table.c.user_id == trans.app.model.User.table.c.id ) ) + clause_list.append( and_( self.app.model.User.table.c.username == owner, + self.app.model.Repository.table.c.user_id == self.app.model.User.table.c.id ) ) if name is not None: - clause_list.append( trans.app.model.Repository.table.c.name == name ) - for repository in trans.sa_session.query( trans.app.model.Repository ) \ + clause_list.append( self.app.model.Repository.table.c.name == name ) + for repository in trans.sa_session.query( self.app.model.Repository ) \ .filter( *clause_list ) \ - .order_by( trans.app.model.Repository.table.c.name ): + .order_by( self.app.model.Repository.table.c.name ): repository_dict = repository.to_dict( view='collection', value_mapper=self.__get_value_mapper( trans ) ) repository_dict[ 'category_ids' ] = \ @@ -471,7 +489,7 @@ class RepositoriesController( BaseAPIController ): owner = payload.get( 'owner', '' ) if not owner: raise HTTPBadRequest( detail="Missing required parameter 'owner'." ) - repository = suc.get_repository_by_name_and_owner( trans.app, name, owner ) + repository = suc.get_repository_by_name_and_owner( self.app, name, owner ) if repository is None: error_message = 'Cannot locate repository with name %s and owner %s,' % ( str( name ), str( owner ) ) log.debug( error_message ) @@ -479,7 +497,7 @@ class RepositoriesController( BaseAPIController ): response_dict[ 'message' ] = error_message return response_dict # Update the repository registry. - trans.app.repository_registry.remove_entry( repository ) + self.app.repository_registry.remove_entry( repository ) response_dict[ 'status' ] = 'ok' response_dict[ 'message' ] = 'Entries for repository %s owned by %s have been removed from the Tool Shed repository registry.' \ % ( name, owner ) @@ -504,7 +522,7 @@ class RepositoriesController( BaseAPIController ): my_writable = True handled_repository_ids = [] repository_ids = [] - rmm = repository_metadata_manager.RepositoryMetadataManager( trans.app, trans.user ) + rmm = repository_metadata_manager.RepositoryMetadataManager( self.app, trans.user ) query = rmm.get_query_for_setting_metadata_on_repositories( my_writable=my_writable, order=False ) # Make sure repositories of type tool_dependency_definition are first in the list. for repository in query: @@ -546,7 +564,7 @@ class RepositoriesController( BaseAPIController ): rmm.reset_all_metadata_on_repository_in_tool_shed() rmm_invalid_file_tups = rmm.get_invalid_file_tups() if rmm_invalid_file_tups: - message = tool_util.generate_message_for_invalid_tools( trans.app, + message = tool_util.generate_message_for_invalid_tools( self.app, rmm_invalid_file_tups, repository, None, @@ -563,7 +581,7 @@ class RepositoriesController( BaseAPIController ): status = '%s : %s' % ( str( repository.name ), message ) results[ 'repository_status' ].append( status ) return results - rmm = repository_metadata_manager.RepositoryMetadataManager( app=trans.app, + rmm = repository_metadata_manager.RepositoryMetadataManager( app=self.app, user=trans.user, resetting_all_metadata_on_repository=True, updating_installed_repository=False, @@ -627,7 +645,7 @@ class RepositoriesController( BaseAPIController ): results = dict( start_time=start_time, repository_status=[] ) try: - rmm = repository_metadata_manager.RepositoryMetadataManager( app=trans.app, + rmm = repository_metadata_manager.RepositoryMetadataManager( app=self.app, user=trans.user, repository=repository, resetting_all_metadata_on_repository=True, @@ -636,7 +654,7 @@ class RepositoriesController( BaseAPIController ): rmm.reset_all_metadata_on_repository_in_tool_shed() rmm_invalid_file_tups = rmm.get_invalid_file_tups() if rmm_invalid_file_tups: - message = tool_util.generate_message_for_invalid_tools( trans.app, + message = tool_util.generate_message_for_invalid_tools( self.app, rmm_invalid_file_tups, repository, None, @@ -656,7 +674,7 @@ class RepositoriesController( BaseAPIController ): repository_id = payload.get( 'repository_id', None ) if repository_id is not None: - repository = suc.get_repository_in_tool_shed( trans.app, repository_id ) + repository = suc.get_repository_in_tool_shed( self.app, repository_id ) start_time = strftime( "%Y-%m-%d %H:%M:%S" ) log.debug( "%s...resetting metadata on repository %s" % ( start_time, str( repository.name ) ) ) results = handle_repository( trans, start_time, repository ) @@ -685,7 +703,7 @@ class RepositoriesController( BaseAPIController ): except Exception: raise MalformedId( 'The given id is invalid.' ) - repository = suc.get_repository_in_tool_shed( trans.app, id ) + repository = suc.get_repository_in_tool_shed( self.app, id ) if repository is None: raise ObjectNotFound( 'Unable to locate repository for the given id.' ) repository_dict = repository.to_dict( view='element', @@ -695,6 +713,37 @@ class RepositoriesController( BaseAPIController ): [ trans.security.encode_id( x.category.id ) for x in repository.categories ] return repository_dict + @expose_api_anonymous_and_sessionless + def show_tools( self, trans, id, changeset, **kwd ): + repository_metadata = suc.get_repository_metadata_by_changeset_revision( self.app, + id, + changeset ) + if repository_metadata is not None: + encoded_repository_metadata_id = trans.security.encode_id( repository_metadata.id ) + repository_metadata_dict = repository_metadata.to_dict( view='collection', + value_mapper=self.__get_value_mapper( trans ) ) + repository_metadata_dict[ 'url' ] = web.url_for( controller='repository_revisions', + action='show', + id=encoded_repository_metadata_id ) + if 'tools' in repository_metadata.metadata: + repository_metadata_dict[ 'valid_tools' ] = repository_metadata.metadata[ 'tools' ] + # 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, \ + has_repository_dependencies_only_if_compiling_contained_td = \ + repository_util.get_repo_info_dict( self.app, + trans.user, + id, + changeset ) + return repository_metadata_dict + else: + log.debug( "Unable to locate repository_metadata record for repository id %s and changeset_revision %s" % + ( str( id ), str( changeset ) ) ) + return {} + @expose_api_anonymous_and_sessionless def metadata( self, trans, id, **kwd ): """ @@ -714,6 +763,7 @@ class RepositoriesController( BaseAPIController ): trans.security.decode_id( id ) except Exception: raise MalformedId( 'The given id is invalid.' ) + recursive = util.asbool( kwd.get( 'recursive', 'True' ) ) all_metadata = {} repository = suc.get_repository_in_tool_shed( self.app, id ) for changeset, changehash in repository.installable_revisions( self.app ): @@ -722,15 +772,15 @@ class RepositoriesController( BaseAPIController ): continue metadata_dict = metadata.to_dict( value_mapper={ 'id': self.app.security.encode_id, 'repository_id': self.app.security.encode_id } ) metadata_dict[ 'repository' ] = repository.to_dict( value_mapper={ 'id': self.app.security.encode_id } ) - if metadata.has_repository_dependencies: + if metadata.has_repository_dependencies and recursive: metadata_dict[ 'repository_dependencies' ] = metadata_util.get_all_dependencies( self.app, metadata, processed_dependency_links=[] ) else: metadata_dict[ 'repository_dependencies' ] = [] - if metadata.includes_tool_dependencies: + if metadata.includes_tool_dependencies and recursive: metadata_dict[ 'tool_dependencies' ] = repository.get_tool_dependencies( changehash ) else: metadata_dict[ 'tool_dependencies' ] = {} - all_metadata[ '%s:%s' % ( changeset, changehash ) ] = metadata_dict + all_metadata[ '%s:%s' % ( int( changeset ), changehash ) ] = metadata_dict return all_metadata @expose_api @@ -779,7 +829,7 @@ class RepositoriesController( BaseAPIController ): category_ids=category_ids, ) - repo, message = repository_util.update_repository( app=trans.app, trans=trans, id=id, **update_kwds ) + repo, message = repository_util.update_repository( app=self.app, trans=trans, id=id, **update_kwds ) if repo is None: if "You are not the owner" in message: raise InsufficientPermissionsException( message ) @@ -835,11 +885,11 @@ class RepositoriesController( BaseAPIController ): if repo_type not in rt_util.types: raise RequestParameterInvalidException( 'This repository type is not valid' ) - invalid_message = repository_util.validate_repository_name( trans.app, name, trans.user ) + invalid_message = repository_util.validate_repository_name( self.app, name, trans.user ) if invalid_message: raise RequestParameterInvalidException( invalid_message ) - repo, message = repository_util.create_repository( app=trans.app, + repo, message = repository_util.create_repository( app=self.app, name=name, type=repo_type, description=synopsis, @@ -871,24 +921,24 @@ class RepositoriesController( BaseAPIController ): """ # Example URL: http://localhost:9009/api/repositories/f9cad7b01a472135 - rdah = attribute_handlers.RepositoryDependencyAttributeHandler( trans.app, unpopulate=False ) - tdah = attribute_handlers.ToolDependencyAttributeHandler( trans.app, unpopulate=False ) + rdah = attribute_handlers.RepositoryDependencyAttributeHandler( self.app, unpopulate=False ) + tdah = attribute_handlers.ToolDependencyAttributeHandler( self.app, unpopulate=False ) - repository = suc.get_repository_in_tool_shed( trans.app, id ) + repository = suc.get_repository_in_tool_shed( self.app, id ) if not ( trans.user_is_admin() or - trans.app.security_agent.user_can_administer_repository( trans.user, repository ) or - trans.app.security_agent.can_push( trans.app, trans.user, repository ) ): + self.app.security_agent.user_can_administer_repository( trans.user, repository ) or + self.app.security_agent.can_push( self.app, trans.user, repository ) ): trans.response.status = 400 return { "err_msg": "You do not have permission to update this repository.", } - repo_dir = repository.repo_path( trans.app ) - repo = hg_util.get_repo_for_repository( trans.app, repository=None, repo_path=repo_dir, create=False ) + repo_dir = repository.repo_path( self.app ) + repo = hg_util.get_repo_for_repository( self.app, repository=None, repo_path=repo_dir, create=False ) upload_point = commit_util.get_upload_point( repository, **kwd ) - tip = repository.tip( trans.app ) + tip = repository.tip( self.app ) file_data = payload.get('file') # Code stolen from gx's upload_common.py @@ -938,12 +988,12 @@ class RepositoriesController( BaseAPIController ): # Update the repository files for browsing. hg_util.update_repository( repo ) # Get the new repository tip. - if tip == repository.tip( trans.app ): + if tip == repository.tip( self.app ): trans.response.status = 400 message = 'No changes to repository.' ok = False else: - rmm = repository_metadata_manager.RepositoryMetadataManager( app=trans.app, + rmm = repository_metadata_manager.RepositoryMetadataManager( app=self.app, user=trans.user, repository=repository ) status, error_message = \ diff --git a/lib/galaxy/webapps/tool_shed/buildapp.py b/lib/galaxy/webapps/tool_shed/buildapp.py index 21430711f61..eab6c3d4d43 100644 --- a/lib/galaxy/webapps/tool_shed/buildapp.py +++ b/lib/galaxy/webapps/tool_shed/buildapp.py @@ -109,12 +109,18 @@ def app_factory( global_conf, **kwargs ): name_prefix='category_', path_prefix='/api', parent_resources=dict( member_name='category', collection_name='categories' ) ) + webapp.mapper.connect( 'repositories_in_category', + '/api/categories/{category_id}/repositories', + controller='categories', + action='get_repositories', + conditions=dict( method=[ "GET" ] ) ) webapp.mapper.resource( 'repository', 'repositories', controller='repositories', collection={ 'add_repository_registry_entry': 'POST', 'get_repository_revision_install_info': 'GET', 'get_ordered_installable_revisions': 'GET', + 'get_installable_revisions': 'GET', 'remove_repository_registry_entry': 'POST', 'repository_ids_for_setting_metadata': 'GET', 'reset_metadata_on_repositories': 'POST', @@ -152,6 +158,11 @@ def app_factory( global_conf, **kwargs ): controller='repositories', action='metadata', conditions=dict( method=[ "GET" ] ) ) + webapp.mapper.connect( 'repository_show_tools', + '/api/repositories/{id}/{changeset}/show_tools', + controller='repositories', + action='show_tools', + conditions=dict( method=[ "GET" ] ) ) webapp.mapper.connect( 'create_repository', '/api/repositories', controller='repositories', diff --git a/lib/galaxy/webapps/tool_shed/controllers/repository.py b/lib/galaxy/webapps/tool_shed/controllers/repository.py index 7d3392d5442..01f2d01380d 100644 --- a/lib/galaxy/webapps/tool_shed/controllers/repository.py +++ b/lib/galaxy/webapps/tool_shed/controllers/repository.py @@ -1618,22 +1618,10 @@ class RepositoryController( BaseUIController, ratings_util.ItemRatings ): owner = kwd.get( 'owner', None ) changeset_revision = kwd.get( 'changeset_revision', None ) repository = suc.get_repository_by_name_and_owner( trans.app, name, owner ) - # We aren't concerned with repositories of type tool_dependency_definition here if a - # repository_metadata record is not returned because repositories of this type will never - # have repository dependencies. However, if a readme file is uploaded, or some other change - # is made that does not create a new downloadable changeset revision but updates the existing - # one, we still want to be able to get repository dependencies. - repository_metadata = suc.get_current_repository_metadata_for_changeset_revision( trans.app, - repository, - changeset_revision ) - if repository_metadata: - metadata = repository_metadata.metadata - if metadata: - toolshed_base_url = str( web.url_for( '/', qualified=True ) ).rstrip( '/' ) - rb = relation_builder.RelationBuilder( trans.app, repository, repository_metadata, toolshed_base_url ) - repository_dependencies = rb.get_repository_dependencies_for_changeset_revision() - if repository_dependencies: - return encoding_util.tool_shed_encode( repository_dependencies ) + # get_repository_dependencies( self, app, changeset, toolshed_url ) + dependencies = repository.get_repository_dependencies( trans.app, changeset_revision, web.url_for( '/', qualified=True ) ) + if dependencies: + return encoding_util.tool_shed_encode( dependencies ) return '' @web.expose @@ -1724,13 +1712,9 @@ class RepositoryController( BaseUIController, ratings_util.ItemRatings ): owner = kwd.get( 'owner', None ) changeset_revision = kwd.get( 'changeset_revision', None ) repository = suc.get_repository_by_name_and_owner( trans.app, name, owner ) - for downloadable_revision in repository.downloadable_revisions: - if downloadable_revision.changeset_revision == changeset_revision: - break - metadata = downloadable_revision.metadata - tool_dependencies = metadata.get( 'tool_dependencies', '' ) - if tool_dependencies: - return encoding_util.tool_shed_encode( tool_dependencies ) + dependencies = repository.get_tool_dependencies( changeset_revision ) + if dependencies is not None: + return encoding_util.tool_shed_encode( dependencies ) return '' @web.expose diff --git a/lib/galaxy/webapps/tool_shed/model/__init__.py b/lib/galaxy/webapps/tool_shed/model/__init__.py index 43c45832b13..f8501ae7d6e 100644 --- a/lib/galaxy/webapps/tool_shed/model/__init__.py +++ b/lib/galaxy/webapps/tool_shed/model/__init__.py @@ -8,8 +8,8 @@ from galaxy.util.bunch import Bunch from galaxy.util.hash_util import new_secure_hash from galaxy.util.dictifiable import Dictifiable import tool_shed.repository_types.util as rt_util -import tool_shed.util.shed_util_common as suc from tool_shed.dependencies.repository import relation_builder +from tool_shed.util import shed_util_common as suc from mercurial import hg from mercurial import ui @@ -253,14 +253,14 @@ class Repository( object, Dictifiable ): def installable_revisions( self, app ): return suc.get_metadata_revisions( self, hg.repository( ui.ui(), self.repo_path( app ) ), sort_revisions=True ) - def ordered_installable_revisions( self, app ): - return suc.get_ordered_metadata_changeset_revisions( self, hg.repository( ui.ui(), self.repo_path( app ) ), downloadable=True ) - def is_new( self, app ): repo = hg.repository( ui.ui(), self.repo_path( app ) ) tip_ctx = repo.changectx( repo.changelog.tip() ) return tip_ctx.rev() < 0 + def ordered_installable_revisions( self, app ): + return suc.get_ordered_metadata_changeset_revisions( self, hg.repository( ui.ui(), self.repo_path( app ) ), downloadable=True ) + def repo_path( self, app ): return app.hgweb_config_manager.get_entry( os.path.join( "repos", self.user.username, self.name ) ) diff --git a/lib/galaxy/webapps/tool_shed/model/mapping.py b/lib/galaxy/webapps/tool_shed/model/mapping.py index 4771958fbb3..ea1570de82b 100644 --- a/lib/galaxy/webapps/tool_shed/model/mapping.py +++ b/lib/galaxy/webapps/tool_shed/model/mapping.py @@ -201,7 +201,7 @@ Category.table = Table( "category", metadata, Column( "create_time", DateTime, default=now ), Column( "update_time", DateTime, default=now, onupdate=now ), Column( "name", TrimmedString( 255 ), index=True, unique=True ), - Column( "description" , TEXT ), + Column( "description", TEXT ), Column( "deleted", Boolean, index=True, default=False ) ) Tag.table = Table( "tag", metadata, diff --git a/lib/tool_shed/util/common_util.py b/lib/tool_shed/util/common_util.py index 14c37001c3e..a3d5f6561ce 100644 --- a/lib/tool_shed/util/common_util.py +++ b/lib/tool_shed/util/common_util.py @@ -341,7 +341,7 @@ def remove_protocol_from_tool_shed_url( tool_shed_url ): return util.remove_protocol_from_url( tool_shed_url ) -def tool_shed_get( app, base_url, pathspec=[], params={} ): +def tool_shed_get( app, base_url, pathspec=None, params=None ): """Make contact with the tool shed via the uri provided.""" registry = app.tool_shed_registry # urllib2 auto-detects system proxies, when passed a Proxyhandler. diff --git a/lib/tool_shed/util/metadata_util.py b/lib/tool_shed/util/metadata_util.py index ce563e3ee00..19f430a59d7 100644 --- a/lib/tool_shed/util/metadata_util.py +++ b/lib/tool_shed/util/metadata_util.py @@ -71,6 +71,11 @@ def get_latest_repository_metadata( app, decoded_repository_id, downloadable=Fal changeset_revision ) +def get_metadata_by_id( app, metadata_id ): + sa_session = app.model.context.current + return sa_session.query( app.model.RepositoryMetadata ).filter( app.model.RepositoryMetadata.table.c.id == metadata_id ).one() + + def get_previous_metadata_changeset_revision( repository, repo, before_changeset_revision, downloadable=True ): """ Return the changeset_revision in the repository changelog that has associated metadata prior to diff --git a/lib/tool_shed/util/repository_util.py b/lib/tool_shed/util/repository_util.py index ac35e838402..035acc46d7b 100644 --- a/lib/tool_shed/util/repository_util.py +++ b/lib/tool_shed/util/repository_util.py @@ -408,6 +408,43 @@ def handle_role_associations( app, role, repository, **kwd ): return associations_dict +def check_for_updates( app, model, repository_id=None ): + message = '' + status = 'ok' + if repository_id is None: + success_count = 0 + repository_names_not_updated = [] + updated_count = 0 + for repository in model.context.query( model.ToolShedRepository ) \ + .filter( model.ToolShedRepository.table.c.deleted == false() ): + ok, updated = \ + check_or_update_tool_shed_status_for_installed_repository( app, repository ) + if ok: + success_count += 1 + else: + repository_names_not_updated.append( '%s' % escape( str( repository.name ) ) ) + if updated: + updated_count += 1 + message = "Checked the status in the tool shed for %d repositories. " % success_count + message += "Updated the tool shed status for %d repositories. " % updated_count + if repository_names_not_updated: + message += "Unable to retrieve status from the tool shed for the following repositories:\n" + message += ", ".join( repository_names_not_updated ) + else: + repository = suc.get_tool_shed_repository_by_id( app, repository_id ) + ok, updated = \ + check_or_update_tool_shed_status_for_installed_repository( app, repository ) + if ok: + if updated: + message = "The tool shed status for repository %s has been updated." % escape( str( repository.name ) ) + else: + message = "The status has not changed in the tool shed for repository %s." % escape( str( repository.name ) ) + else: + message = "Unable to retrieve status from the tool shed for repository %s." % escape( str( repository.name ) ) + status = 'error' + return message, status + + def validate_repository_name( app, name, user ): """ Validate whether the given name qualifies as a new TS repo name. diff --git a/lib/tool_shed/util/shed_util_common.py b/lib/tool_shed/util/shed_util_common.py index da2b99376ae..95f6d18f0e7 100644 --- a/lib/tool_shed/util/shed_util_common.py +++ b/lib/tool_shed/util/shed_util_common.py @@ -341,7 +341,9 @@ def get_ids_of_tool_shed_repositories_being_installed( app, as_string=False ): return installing_repository_ids -def get_latest_downloadable_changeset_revision( app, repository, repo ): +def get_latest_downloadable_changeset_revision( app, repository, repo=None ): + if repo is None: + repo = hg_util.get_repo_for_repository( app, repository=repository, repo_path=None, create=False ) repository_tip = repository.tip( app ) repository_metadata = get_repository_metadata_by_changeset_revision( app, app.security.encode_id( repository.id ), repository_tip ) if repository_metadata and repository_metadata.downloadable: @@ -365,6 +367,21 @@ def get_tool_dependency_definition_metadata_from_tool_shed( app, tool_shed_url, return metadata +def get_metadata_changeset_revisions( repository, repo ): + """ + Return an unordered list of changeset_revisions and changeset numbers that are defined as installable. + """ + changeset_tups = [] + for repository_metadata in repository.downloadable_revisions: + ctx = hg_util.get_changectx_for_changeset( repo, repository_metadata.changeset_revision ) + if ctx: + rev = ctx.rev() + else: + rev = -1 + changeset_tups.append( ( rev, repository_metadata.changeset_revision ) ) + return sorted( changeset_tups ) + + def get_next_downloadable_changeset_revision( repository, repo, after_changeset_revision ): """ Return the installable changeset_revision in the repository changelog after the changeset to which @@ -477,6 +494,22 @@ def get_repo_info_tuple_contents( repo_info_tuple ): return description, repository_clone_url, changeset_revision, ctx_rev, repository_owner, repository_dependencies, tool_dependencies +def get_repositories_by_category( app, category_id ): + sa_session = app.model.context.current + resultset = sa_session.query( app.model.Category ).get( category_id ) + repositories = [] + default_value_mapper = { 'id': app.security.encode_id, 'user_id': app.security.encode_id } + for row in resultset.repositories: + repository_dict = row.repository.to_dict( value_mapper=default_value_mapper ) + repository_dict[ 'metadata' ] = {} + for changeset, changehash in row.repository.installable_revisions( app ): + encoded_id = app.security.encode_id( row.repository.id ) + metadata = get_repository_metadata_by_changeset_revision( app, encoded_id, changehash ) + repository_dict[ 'metadata' ][ '%s:%s' % ( changeset, changehash ) ] = metadata.to_dict( value_mapper=default_value_mapper ) + repositories.append( repository_dict ) + return repositories + + def get_repository_and_repository_dependencies_from_repo_info_dict( app, repo_info_dict ): """Return a tool_shed_repository or repository record defined by the information in the received repo_info_dict.""" repository_name = repo_info_dict.keys()[ 0 ] diff --git a/lib/tool_shed/util/tool_util.py b/lib/tool_shed/util/tool_util.py index 72bc36c331a..af2ab8d70bd 100644 --- a/lib/tool_shed/util/tool_util.py +++ b/lib/tool_shed/util/tool_util.py @@ -34,7 +34,7 @@ def build_tool_panel_section_select_field( app ): options = [] for section_id, section_name in app.toolbox.get_sections(): options.append( ( section_name, section_id ) ) - select_field = SelectField( name='tool_panel_section_id', display='radio' ) + select_field = SelectField( name='tool_panel_section_id', field_id='tool_panel_section_select' ) for option_tup in options: select_field.add_option( option_tup[ 0 ], option_tup[ 1 ] ) return select_field diff --git a/test/tool_shed/functional/test_1040_install_repository_basic_circular_dependencies.py b/test/tool_shed/functional/test_1040_install_repository_basic_circular_dependencies.py index c0c29b7263e..ee47d169eed 100644 --- a/test/tool_shed/functional/test_1040_install_repository_basic_circular_dependencies.py +++ b/test/tool_shed/functional/test_1040_install_repository_basic_circular_dependencies.py @@ -108,7 +108,7 @@ class TestInstallingCircularDependencies( ShedTwillTestCase ): self.display_installed_repository_manage_page( installed_filtering_repository ) self.deactivate_repository( installed_filtering_repository ) self.test_db_util.ga_refresh( installed_filtering_repository ) - self.check_galaxy_repository_tool_panel_section( installed_filtering_repository, '' ) + self.check_galaxy_repository_tool_panel_section( installed_filtering_repository, 'Get Data' ) strings_displayed = [ 'Missing repository', 'filtering', 'freebayes_0040', 'user1', "Galaxy's freebayes tool for test 0040" ] self.display_installed_repository_manage_page( installed_freebayes_repository, strings_displayed=strings_displayed ) self.check_galaxy_repository_db_status( filtering_repository_name, @@ -133,7 +133,7 @@ class TestInstallingCircularDependencies( ShedTwillTestCase ): self.display_installed_repository_manage_page( installed_filtering_repository ) self.deactivate_repository( installed_freebayes_repository ) self.test_db_util.ga_refresh( installed_freebayes_repository ) - self.check_galaxy_repository_tool_panel_section( installed_freebayes_repository, '' ) + self.check_galaxy_repository_tool_panel_section( installed_freebayes_repository, 'Get Data' ) strings_displayed = [ 'Missing repository', 'freebayes', 'filtering_0040', 'user1', "Galaxy's filtering tool for test 0040" ] self.display_installed_repository_manage_page( installed_filtering_repository, strings_displayed=strings_displayed ) self.check_galaxy_repository_db_status( 'freebayes_0040', @@ -148,7 +148,7 @@ class TestInstallingCircularDependencies( ShedTwillTestCase ): self.display_installed_repository_manage_page( installed_filtering_repository ) self.deactivate_repository( installed_filtering_repository ) self.test_db_util.ga_refresh( installed_filtering_repository ) - self.check_galaxy_repository_tool_panel_section( installed_filtering_repository, '' ) + self.check_galaxy_repository_tool_panel_section( installed_filtering_repository, 'Get Data' ) strings_displayed = [ 'Missing repository', 'filtering', 'freebayes_0040', 'user1', "Galaxy's freebayes tool for test 0040" ] self.display_installed_repository_manage_page( installed_freebayes_repository, strings_displayed=strings_displayed ) self.check_galaxy_repository_db_status( filtering_repository_name,