1 new commit in galaxy-central: https://bitbucket.org/galaxy/galaxy-central/commits/5a41d725197d/ Changeset: 5a41d725197d User: greg Date: 2013-07-11 20:59:27 Summary: Add support for categorizing repositories in the tool shed by type, with the first 2 supported types being "generic" and "tool_dependency_definition". Repositories of type "tool_dependency_definition" can always contain only a single file named "tool_dependencies.xml", and the only metadata revision for these types of repositories will be the changelog tip. Affected #: 20 files diff -r 92225a7b6e5ecd87410f1da567b9e320b965be50 -r 5a41d725197d2d42475f80282a57b0b364898671 lib/galaxy/webapps/tool_shed/app.py --- a/lib/galaxy/webapps/tool_shed/app.py +++ b/lib/galaxy/webapps/tool_shed/app.py @@ -7,6 +7,7 @@ from galaxy.openid.providers import OpenIDProviders from galaxy.web import security from galaxy.tags.tag_handler import CommunityTagHandler +import tool_shed.repository_types.registry class UniverseApplication( object ): """Encapsulates the state of a Universe application""" @@ -20,6 +21,8 @@ # Set up datatypes registry self.datatypes_registry = galaxy.datatypes.registry.Registry() self.datatypes_registry.load_datatypes( self.config.root, self.config.datatypes_config ) + # Set up the repository_types registry. + self.repository_types_registry = tool_shed.repository_types.registry.Registry() # Determine the database url if self.config.database_connection: db_url = self.config.database_connection diff -r 92225a7b6e5ecd87410f1da567b9e320b965be50 -r 5a41d725197d2d42475f80282a57b0b364898671 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 @@ -35,6 +35,7 @@ import galaxy.tools import tool_shed.grids.repository_grids as repository_grids import tool_shed.grids.util as grids_util +import tool_shed.repository_types.util as rt_util from galaxy import eggs eggs.require('mercurial') @@ -665,10 +666,12 @@ # Update repository files for browsing. suc.update_repository( repo ) metadata = self.get_metadata( trans, id, repository.tip( trans.app ) ) + repository_type_select_field = rt_util.build_repository_type_select_fiels( trans, repository=repository ) return trans.fill_template( '/webapps/tool_shed/repository/browse_repository.mako', repository=repository, metadata=metadata, commit_message=commit_message, + repository_type_select_field=repository_type_select_field, message=message, status=status ) @@ -961,6 +964,7 @@ long_description = kwd.get( 'long_description', '' ) category_ids = util.listify( kwd.get( 'category_id', '' ) ) selected_categories = [ trans.security.decode_id( id ) for id in category_ids ] + repository_type = kwd.get( 'repository_type', rt_util.GENERIC ) if kwd.get( 'create_repository_button', False ): error = False message = self.__validate_repository_name( name, trans.user ) @@ -974,6 +978,7 @@ else: # Add the repository record to the db repository = trans.app.model.Repository( name=name, + type=repository_type, description=description, long_description=long_description, user_id=trans.user.id ) @@ -1001,7 +1006,7 @@ if category_ids: # Create category associations for category_id in category_ids: - category = trans.sa_session.query(model.Category).get( trans.security.decode_id( category_id ) ) + category = trans.sa_session.query( model.Category ).get( trans.security.decode_id( category_id ) ) rca = trans.app.model.RepositoryCategoryAssociation( repository, category ) trans.sa_session.add( rca ) flush_needed = True @@ -1012,12 +1017,14 @@ action='view_repository', message=message, id=trans.security.encode_id( repository.id ) ) ) + repository_type_select_field = rt_util.build_repository_type_select_fiels( trans ) return trans.fill_template( '/webapps/tool_shed/repository/create_repository.mako', name=name, description=description, long_description=long_description, selected_categories=selected_categories, categories=categories, + repository_type_select_field=repository_type_select_field, message=message, status=status ) @@ -1985,6 +1992,7 @@ message = kwd.get( 'message', '' ) status = kwd.get( 'status', 'done' ) repository = suc.get_repository_in_tool_shed( trans, id ) + repository_type = kwd.get( 'repository_type', str( repository.type ) ) repo_dir = repository.repo_path( trans.app ) repo = hg.repository( suc.get_configured_ui(), repo_dir ) repo_name = kwd.get( 'repo_name', repository.name ) @@ -2016,6 +2024,9 @@ id=id, message=message, status='error' ) ) + if repository_type != repository.type: + repository.type = repository_type + flush_needed = True if description != repository.description: repository.description = description flush_needed = True @@ -2174,6 +2185,7 @@ else: message += malicious_error status = 'error' + repository_type_select_field = rt_util.build_repository_type_select_fiels( trans, repository=repository ) malicious_check_box = CheckboxField( 'malicious', checked=is_malicious ) skip_tool_tests_check_box = CheckboxField( 'skip_tool_tests', checked=skip_tool_tests_checked ) categories = suc.get_categories( trans ) @@ -2202,6 +2214,7 @@ skip_tool_tests_check_box=skip_tool_tests_check_box, skip_tool_test=skip_tool_test, malicious_check_box=malicious_check_box, + repository_type_select_field=repository_type_select_field, message=message, status=status ) @@ -2352,6 +2365,7 @@ display_reviews = util.string_as_bool( kwd.get( 'display_reviews', False ) ) rra = self.get_user_item_rating( trans.sa_session, trans.user, repository, webapp_model=trans.model ) metadata = self.get_metadata( trans, id, repository.tip( trans.app ) ) + repository_type_select_field = rt_util.build_repository_type_select_fiels( trans, repository=repository ) return trans.fill_template( '/webapps/tool_shed/repository/rate_repository.mako', repository=repository, metadata=metadata, @@ -2359,6 +2373,7 @@ display_reviews=display_reviews, num_ratings=num_ratings, rra=rra, + repository_type_select_field=repository_type_select_field, message=message, status=status ) @@ -2550,10 +2565,12 @@ else: message = "Select at least 1 file to delete from the repository before clicking <b>Delete selected files</b>." status = "error" + repository_type_select_field = rt_util.build_repository_type_select_fiels( trans, repository=repository ) return trans.fill_template( '/webapps/tool_shed/repository/browse_repository.mako', repo=repo, repository=repository, commit_message=commit_message, + repository_type_select_field=repository_type_select_field, message=message, status=status ) @@ -2974,6 +2991,7 @@ message += malicious_error status = 'error' containers_dict = container_util.build_repository_containers_for_tool_shed( trans, repository, changeset_revision, repository_dependencies, repository_metadata ) + repository_type_select_field = rt_util.build_repository_type_select_fiels( trans, repository=repository ) return trans.fill_template( '/webapps/tool_shed/repository/view_repository.mako', repo=repo, repository=repository, @@ -2987,6 +3005,7 @@ changeset_revision=changeset_revision, changeset_revision_select_field=changeset_revision_select_field, revision_label=revision_label, + repository_type_select_field=repository_type_select_field, message=message, status=status ) diff -r 92225a7b6e5ecd87410f1da567b9e320b965be50 -r 5a41d725197d2d42475f80282a57b0b364898671 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 @@ -5,6 +5,7 @@ from galaxy.util.bunch import Bunch from galaxy.util.hash_util import new_secure_hash from galaxy.model.item_attrs import APIItem +import tool_shed.repository_types.util as rt_util from galaxy import eggs eggs.require( 'mercurial' ) @@ -130,18 +131,20 @@ class Repository( object, APIItem ): - api_collection_visible_keys = ( 'id', 'name', 'description', 'user_id', 'private', 'deleted', 'times_downloaded', 'deprecated' ) - api_element_visible_keys = ( 'id', 'name', 'description', 'long_description', 'user_id', 'private', 'deleted', 'times_downloaded', 'deprecated' ) + api_collection_visible_keys = ( 'id', 'name', 'type', 'description', 'user_id', 'private', 'deleted', 'times_downloaded', 'deprecated' ) + api_element_visible_keys = ( 'id', 'name', 'type', 'description', 'long_description', 'user_id', 'private', 'deleted', 'times_downloaded', + 'deprecated' ) file_states = Bunch( NORMAL = 'n', NEEDS_MERGING = 'm', MARKED_FOR_REMOVAL = 'r', MARKED_FOR_ADDITION = 'a', NOT_TRACKED = '?' ) - def __init__( self, id=None, name=None, description=None, long_description=None, user_id=None, private=False, deleted=None, email_alerts=None, - times_downloaded=0, deprecated=False ): + def __init__( self, id=None, name=None, type=None, description=None, long_description=None, user_id=None, private=False, deleted=None, + email_alerts=None, times_downloaded=0, deprecated=False ): self.id = id self.name = name or "Unnamed repository" + self.type = type self.description = description self.long_description = long_description self.user_id = user_id @@ -154,6 +157,24 @@ def as_dict( self, value_mapper=None ): return self.get_api_value( view='element', value_mapper=value_mapper ) + def can_change_type( self, app ): + # Allow changing the type only if the repository has no contents, has never been installed, or has never been changed from + # the default type. + if self.is_new( app ): + return True + if self.times_downloaded == 0: + return True + if self.type == rt_util.DEFAULT: + return True + return False + + def can_change_type_to( self, app, new_type_label ): + if self.can_change_type( app ): + new_type = app.repository_types_registry.get_class_by_label( new_type_label ) + if new_type.is_valid_for_type( self ): + return True + return False + def get_api_value( self, view='collection', value_mapper=None ): if value_mapper is None: value_mapper = {} @@ -173,6 +194,13 @@ rval[ 'owner' ] = self.user.username return rval + def get_changesets_for_setting_metadata( self, app ): + type_class = self.get_type_class( app ) + return type_class.get_changesets_for_setting_metadata( app, self ) + + def get_type_class( self, app ): + return app.repository_types_registry.get_class_by_label( self.type ) + def repo_path( self, app ): return app.hgweb_config_manager.get_entry( os.path.join( "repos", self.user.username, self.name ) ) diff -r 92225a7b6e5ecd87410f1da567b9e320b965be50 -r 5a41d725197d2d42475f80282a57b0b364898671 lib/galaxy/webapps/tool_shed/model/mapping.py --- a/lib/galaxy/webapps/tool_shed/model/mapping.py +++ b/lib/galaxy/webapps/tool_shed/model/mapping.py @@ -106,6 +106,7 @@ Column( "create_time", DateTime, default=now ), Column( "update_time", DateTime, default=now, onupdate=now ), Column( "name", TrimmedString( 255 ), index=True ), + Column( "type", TrimmedString( 255 ), index=True ), Column( "description" , TEXT ), Column( "long_description" , TEXT ), Column( "user_id", Integer, ForeignKey( "galaxy_user.id" ), index=True ), diff -r 92225a7b6e5ecd87410f1da567b9e320b965be50 -r 5a41d725197d2d42475f80282a57b0b364898671 lib/galaxy/webapps/tool_shed/model/migrate/versions/0020_add_repository_type_column.py --- /dev/null +++ b/lib/galaxy/webapps/tool_shed/model/migrate/versions/0020_add_repository_type_column.py @@ -0,0 +1,46 @@ +"""Migration script to add the type column to the repository table.""" + +from sqlalchemy import * +from sqlalchemy.orm import * +from migrate import * +from migrate.changeset import * + +# Need our custom types, but don't import anything else from model +from galaxy.model.custom_types import * + +import sys, logging +log = logging.getLogger( __name__ ) +log.setLevel(logging.DEBUG) +handler = logging.StreamHandler( sys.stdout ) +format = "%(name)s %(levelname)s %(asctime)s %(message)s" +formatter = logging.Formatter( format ) +handler.setFormatter( formatter ) +log.addHandler( handler ) + +metadata = MetaData() + +def upgrade( migrate_engine ): + print __doc__ + metadata.bind = migrate_engine + metadata.reflect() + Repository_table = Table( "repository", metadata, autoload=True ) + c = Column( "type", TrimmedString( 255 ), index=True ) + try: + # Create + c.create( Repository_table, index_name="ix_repository_type" ) + assert c is Repository_table.c.type + except Exception, e: + print "Adding type column to the repository table failed: %s" % str( e ) + # Update the type column to have the default generic value. + cmd = "UPDATE repository SET type = 'generic'" + migrate_engine.execute( cmd ) + +def downgrade( migrate_engine ): + metadata.bind = migrate_engine + metadata.reflect() + # Drop type column from repository table. + Repository_table = Table( "repository", metadata, autoload=True ) + try: + Repository_table.c.type.drop() + except Exception, e: + print "Dropping column type from the repository table failed: %s" % str( e ) diff -r 92225a7b6e5ecd87410f1da567b9e320b965be50 -r 5a41d725197d2d42475f80282a57b0b364898671 lib/tool_shed/repository_types/generic.py --- /dev/null +++ b/lib/tool_shed/repository_types/generic.py @@ -0,0 +1,20 @@ +import logging +import tool_shed.repository_types.util as rt_util +from tool_shed.repository_types.metadata import Metadata + +log = logging.getLogger( __name__ ) + + +class Generic( Metadata ): + + def __init__( self ): + self.type = rt_util.GENERIC + self.label = 'Generic' + + def is_valid_for_type( self, app, repository, revisions_to_check=None ): + """A repository's type can only be changed to the generic type if it is new or has never been installed.""" + if repository.is_new( app ): + return True + if repository.times_downloaded == 0: + return True + return False diff -r 92225a7b6e5ecd87410f1da567b9e320b965be50 -r 5a41d725197d2d42475f80282a57b0b364898671 lib/tool_shed/repository_types/metadata.py --- /dev/null +++ b/lib/tool_shed/repository_types/metadata.py @@ -0,0 +1,32 @@ +import logging +import tool_shed.repository_types.util as rt_util + +from galaxy import eggs +eggs.require( 'mercurial' ) +from mercurial import hg +from mercurial import ui + +log = logging.getLogger( __name__ ) + + +class Metadata( object ): + + def __init__( self ): + self.type = None + + def get_changesets_for_setting_metadata( self, app, repository ): + repo = hg.repository( ui.ui(), repository.repo_path( app ) ) + return repo.changelog + + def is_valid_for_type( self, repository, revisions_to_check=None ): + raise "Unimplemented Method" + + +class TipOnly( Metadata ): + + def __init__( self ): + self.type = None + + def get_changesets_for_setting_metadata( self, app, repository ): + repo = hg.repository( ui.ui(), repository.repo_path( app ) ) + return [ repo.changelog.tip() ] diff -r 92225a7b6e5ecd87410f1da567b9e320b965be50 -r 5a41d725197d2d42475f80282a57b0b364898671 lib/tool_shed/repository_types/registry.py --- /dev/null +++ b/lib/tool_shed/repository_types/registry.py @@ -0,0 +1,17 @@ +import logging +import generic +import tool_dependency_definition +from galaxy.util.odict import odict + +log = logging.getLogger( __name__ ) + + +class Registry( object ): + + def __init__( self ): + self.repository_types_by_label = odict() + self.repository_types_by_label[ 'generic' ] = generic.Generic() + self.repository_types_by_label[ 'tool_dependency_definition' ] = tool_dependency_definition.ToolDependencyDefinition() + + def get_class_by_label( self, label ): + return self.repository_types_by_label.get( label, None ) diff -r 92225a7b6e5ecd87410f1da567b9e320b965be50 -r 5a41d725197d2d42475f80282a57b0b364898671 lib/tool_shed/repository_types/tool_dependency_definition.py --- /dev/null +++ b/lib/tool_shed/repository_types/tool_dependency_definition.py @@ -0,0 +1,43 @@ +import logging +from tool_shed.repository_types.metadata import TipOnly +import tool_shed.repository_types.util as rt_util +import tool_shed.util.shed_util_common as suc + +from galaxy import eggs +eggs.require( 'mercurial' ) +from mercurial import hg +from mercurial import ui + +log = logging.getLogger( __name__ ) + +class ToolDependencyDefinition( TipOnly ): + + def __init__( self ): + self.type = rt_util.TOOL_DEPENDENCY_DEFINITION + self.label = 'Tool dependency definition' + self.valid_file_names = [ 'tool_dependencies.xml' ] + + def is_valid_for_type( self, app, repository, revisions_to_check=None ): + """ + Inspect the received repository's contents to determine if they abide by the rules defined for the contents of this type. + If the received revisions_to_check is a list of changeset revisions, then inspection will be restricted to the revisions + in the list. + """ + repo = hg.repository( ui.ui(), repository.repo_path( app ) ) + if revisions_to_check: + changeset_revisions = revisions_to_check + else: + changeset_revisions = repo.changelog + for changeset in changeset_revisions: + changeset_revision = str( repo.changectx( changeset ) ) + ctx = repo.changectx( changeset ) + # Inspect all files in the changeset (in sorted order) to make sure there is only one and it is named tool_dependencies.xml. + files_changed_in_changeset = ctx.files() + if len( files_changed_in_changeset ) > 1: + return False + for file_path in files_changed_in_changeset: + file_name = suc.strip_path( file_path ) + if file_name not in self.valid_file_names: + return False + return True + \ No newline at end of file diff -r 92225a7b6e5ecd87410f1da567b9e320b965be50 -r 5a41d725197d2d42475f80282a57b0b364898671 lib/tool_shed/repository_types/util.py --- /dev/null +++ b/lib/tool_shed/repository_types/util.py @@ -0,0 +1,30 @@ +import logging +from galaxy.web.form_builder import SelectField + +log = logging.getLogger( __name__ ) + +GENERIC = 'generic' +TOOL_DEPENDENCY_DEFINITION = 'tool_dependency_definition' + +types = [ GENERIC, TOOL_DEPENDENCY_DEFINITION ] + +def build_repository_type_select_fiels( trans, repository=None, name='repository_type' ): + """Called from the Tool Shed to generate the current list of supported repository types.""" + if repository: + selected_type = str( repository.type ) + else: + selected_type = None + repository_type_select_fiels = SelectField( name=name ) + for type_label, type_class in trans.app.repository_types_registry.repository_types_by_label.items(): + option_label = str( type_class.label ) + option_value = str( type_class.type ) + if selected_type and selected_type == option_value: + selected = True + else: + selected = False + if repository: + if type_class.is_valid_for_type( trans.app, repository ): + repository_type_select_fiels.add_option( option_label, option_value, selected=selected ) + else: + repository_type_select_fiels.add_option( option_label, option_value, selected=selected ) + return repository_type_select_fiels diff -r 92225a7b6e5ecd87410f1da567b9e320b965be50 -r 5a41d725197d2d42475f80282a57b0b364898671 lib/tool_shed/util/metadata_util.py --- a/lib/tool_shed/util/metadata_util.py +++ b/lib/tool_shed/util/metadata_util.py @@ -12,6 +12,7 @@ from galaxy.web import url_for from galaxy.webapps.tool_shed.util import container_util import tool_shed.util.shed_util_common as suc +from tool_shed.repository_types.metadata import TipOnly from tool_shed.util import common_util from tool_shed.util import common_install_util from tool_shed.util import readme_util @@ -65,7 +66,7 @@ trans.sa_session.delete( repository_metadata ) trans.sa_session.flush() -def compare_changeset_revisions( ancestor_changeset_revision, ancestor_metadata_dict, current_changeset_revision, current_metadata_dict ): +def compare_changeset_revisions( trans, ancestor_changeset_revision, ancestor_metadata_dict, current_changeset_revision, current_metadata_dict ): """Compare the contents of two changeset revisions to determine if a new repository metadata revision should be created.""" # The metadata associated with ancestor_changeset_revision is ancestor_metadata_dict. This changeset_revision is an ancestor of # current_changeset_revision which is associated with current_metadata_dict. A new repository_metadata record will be created only @@ -104,11 +105,11 @@ # Uncomment the following if we decide that README files should affect how installable repository revisions are defined. See the NOTE in the # compare_readme_files() method. # readme_file_comparision = compare_readme_files( ancestor_readme_files, current_readme_files ) - repository_dependency_comparison = compare_repository_dependencies( ancestor_repository_dependencies, current_repository_dependencies ) - tool_dependency_comparison = compare_tool_dependencies( ancestor_tool_dependencies, current_tool_dependencies ) - workflow_comparison = compare_workflows( ancestor_workflows, current_workflows ) - datatype_comparison = compare_datatypes( ancestor_datatypes, current_datatypes ) - data_manager_comparison = compare_data_manager( ancestor_data_manager, current_data_manager ) + repository_dependency_comparison = compare_repository_dependencies( trans, ancestor_repository_dependencies, current_repository_dependencies ) + tool_dependency_comparison = compare_tool_dependencies( trans, ancestor_tool_dependencies, current_tool_dependencies ) + workflow_comparison = compare_workflows( trans, ancestor_workflows, current_workflows ) + datatype_comparison = compare_datatypes( trans, ancestor_datatypes, current_datatypes ) + data_manager_comparison = compare_data_manager( trans, ancestor_data_manager, current_data_manager ) # Handle case where all metadata is the same. if ancestor_guids == current_guids and \ repository_dependency_comparison == EQUAL and \ @@ -134,7 +135,7 @@ return SUBSET return NOT_EQUAL_AND_NOT_SUBSET -def compare_data_manager( ancestor_metadata, current_metadata ): +def compare_data_manager( trans, ancestor_metadata, current_metadata ): """Determine if ancestor_metadata is the same as or a subset of current_metadata for data_managers.""" def __data_manager_dict_to_tuple_list( metadata_dict ): # we do not check tool_guid or tool conf file name @@ -149,7 +150,7 @@ return SUBSET return NOT_EQUAL_AND_NOT_SUBSET -def compare_datatypes( ancestor_datatypes, current_datatypes ): +def compare_datatypes( trans, ancestor_datatypes, current_datatypes ): """Determine if ancestor_datatypes is the same as or a subset of current_datatypes.""" # Each datatype dict looks something like: {"dtype": "galaxy.datatypes.images:Image", "extension": "pdf", "mimetype": "application/pdf"} if len( ancestor_datatypes ) <= len( current_datatypes ): @@ -193,7 +194,7 @@ return SUBSET return NOT_EQUAL_AND_NOT_SUBSET -def compare_repository_dependencies( ancestor_repository_dependencies, current_repository_dependencies ): +def compare_repository_dependencies( trans, ancestor_repository_dependencies, current_repository_dependencies ): """Determine if ancestor_repository_dependencies is the same as or a subset of current_repository_dependencies.""" # The list of repository_dependencies looks something like: [["http://localhost:9009", "emboss_datatypes", "test", "ab03a2a5f407", False]]. # Create a string from each tuple in the list for easier comparison. @@ -211,14 +212,18 @@ found_in_current = True break if not found_in_current: - return NOT_EQUAL_AND_NOT_SUBSET + # In some cases, the only difference between a dependency definition in the lists is the changeset_revision value. We'll + # check to see if this is the case, and if the defined dependency is a repository that has metadata set only on it's tip. + if not different_revision_defines_tip_only_repository_dependency( ancestor_tup, current_repository_dependencies ): + return NOT_EQUAL_AND_NOT_SUBSET + return SUBSET if len( ancestor_repository_dependencies ) == len( current_repository_dependencies ): return EQUAL else: return SUBSET return NOT_EQUAL_AND_NOT_SUBSET -def compare_tool_dependencies( ancestor_tool_dependencies, current_tool_dependencies ): +def compare_tool_dependencies( trans, ancestor_tool_dependencies, current_tool_dependencies ): """Determine if ancestor_tool_dependencies is the same as or a subset of current_tool_dependencies.""" # The tool_dependencies dictionary looks something like: # {'bwa/0.5.9': {'readme': 'some string', 'version': '0.5.9', 'type': 'package', 'name': 'bwa'}} @@ -238,7 +243,7 @@ return SUBSET return NOT_EQUAL_AND_NOT_SUBSET -def compare_workflows( ancestor_workflows, current_workflows ): +def compare_workflows( trans, ancestor_workflows, current_workflows ): """Determine if ancestor_workflows is the same as current_workflows or if ancestor_workflows is a subset of current_workflows.""" if len( ancestor_workflows ) <= len( current_workflows ): for ancestor_workflow_tup in ancestor_workflows: @@ -341,6 +346,21 @@ break return repository_metadata +def different_revision_defines_tip_only_repository_dependency( rd_tup, repository_dependencies ): + """ + Determine if the only difference between rd_tup and a dependency definition in the list of repository_dependencies is the changeset_revision value. + """ + new_metadata_required = False + rd_tool_shed, rd_name, rd_owner, rd_changeset_revision, rd_prior_installation_required = suc.parse_repository_dependency_tuple( rd_tup ) + for repository_dependency in repository_dependencies: + tool_shed, name, owner, changeset_revision, prior_installation_required = suc.parse_repository_dependency_tuple( repository_dependency ) + if rd_tool_shed == tool_shed and rd_name == name and rd_owner == owner: + # Determine if the repository represented by the dependency tuple is an instance of the repository type TipOnly. + required_repository = suc.get_repository_by_name_and_owner( trans.app, name, owner ) + repository_type_class = trans.app.repository_types_registry.get_class_by_label( required_repository.type ) + return isinstance( repository_type_class, TipOnly ) + return False + def generate_data_manager_metadata( app, repository, repo_dir, data_manager_config_filename, metadata_dict, shed_config_dict=None ): """Update the received metadata_dict with information from the parsed data_manager_config_filename.""" if data_manager_config_filename is None: @@ -1308,7 +1328,10 @@ # The saved metadata must be a subset of the new metadata. for saved_repository_dependency in saved_repository_dependencies: if saved_repository_dependency not in new_repository_dependencies: - return True + # In some cases, the only difference between a dependency definition in the lists is the changeset_revision value. We'll + # check to see if this is the case, and if the defined dependency is a repository that has metadata set only on it's tip. + if not different_revision_defines_tip_only_repository_dependency( saved_repository_dependency, new_repository_dependencies ): + return True return False else: # The repository_dependencies.xml file must have been deleted, so create a new repository_metadata record so we always have @@ -1588,7 +1611,7 @@ ancestor_metadata_dict = None invalid_file_tups = [] home_dir = os.getcwd() - for changeset in repo.changelog: + for changeset in repository.get_changesets_for_setting_metadata( trans.app ): work_dir = tempfile.mkdtemp( prefix="tmp-toolshed-ramorits" ) current_changeset_revision = str( repo.changectx( changeset ) ) ctx = repo.changectx( changeset ) @@ -1619,7 +1642,8 @@ # EQUAL - ancestor metadata is equivalent to current metadata, so continue from current # SUBSET - ancestor metadata is a subset of current metadata, so continue from current # NOT_EQUAL_AND_NOT_SUBSET - ancestor metadata is neither equal to nor a subset of current metadata, so persist ancestor metadata. - comparison = compare_changeset_revisions( ancestor_changeset_revision, + comparison = compare_changeset_revisions( trans, + ancestor_changeset_revision, ancestor_metadata_dict, current_changeset_revision, current_metadata_dict ) @@ -1752,7 +1776,9 @@ persist=False ) if metadata_dict: repository_metadata = None - if new_metadata_required_for_utilities( trans, repository, metadata_dict ): + repository_type_class = trans.app.repository_types_registry.get_class_by_label( repository.type ) + tip_only = isinstance( repository_type_class, TipOnly ) + if not tip_only and new_metadata_required_for_utilities( trans, repository, metadata_dict ): # Create a new repository_metadata table row. repository_metadata = create_or_update_repository_metadata( trans, encoded_id, repository, repository.tip( trans.app ), metadata_dict ) # If this is the first record stored for this repository, see if we need to send any email alerts. diff -r 92225a7b6e5ecd87410f1da567b9e320b965be50 -r 5a41d725197d2d42475f80282a57b0b364898671 templates/webapps/tool_shed/admin/index.mako --- a/templates/webapps/tool_shed/admin/index.mako +++ b/templates/webapps/tool_shed/admin/index.mako @@ -46,7 +46,7 @@ <div class="unified-panel-header" unselectable="on"><div class='unified-panel-header-inner'>Administration</div></div> - <div class="unified-panel-body" style="padding: 10px; overflow: auto;"> + <div class="unified-panel-body"><div class="toolMenu"><div class="toolSectionList"><div class="toolSectionTitle"> diff -r 92225a7b6e5ecd87410f1da567b9e320b965be50 -r 5a41d725197d2d42475f80282a57b0b364898671 templates/webapps/tool_shed/index.mako --- a/templates/webapps/tool_shed/index.mako +++ b/templates/webapps/tool_shed/index.mako @@ -46,7 +46,7 @@ <div class="unified-panel-header" unselectable="on"><div class='unified-panel-header-inner'>${trans.app.shed_counter.valid_tools | h} valid tools on ${trans.app.shed_counter.generation_time | h}</div></div> - <div class="unified-panel-body" style="padding: 10px; overflow: auto;"> + <div class="unified-panel-body"><div class="toolMenu"><div class="toolSectionList"> %if user_id or repository_id: diff -r 92225a7b6e5ecd87410f1da567b9e320b965be50 -r 5a41d725197d2d42475f80282a57b0b364898671 templates/webapps/tool_shed/repository/browse_repository.mako --- a/templates/webapps/tool_shed/repository/browse_repository.mako +++ b/templates/webapps/tool_shed/repository/browse_repository.mako @@ -46,6 +46,7 @@ ${render_clone_str( repository )} </div> %endif + ${render_repository_type_select_field( repository_type_select_field, render_help=False )} %if can_push: <form name="select_files_to_delete" id="select_files_to_delete" action="${h.url_for( controller='repository', action='select_files_to_delete', id=trans.security.encode_id( repository.id ))}" method="post" ><div class="form-row" > diff -r 92225a7b6e5ecd87410f1da567b9e320b965be50 -r 5a41d725197d2d42475f80282a57b0b364898671 templates/webapps/tool_shed/repository/common.mako --- a/templates/webapps/tool_shed/repository/common.mako +++ b/templates/webapps/tool_shed/repository/common.mako @@ -163,6 +163,46 @@ </script></%def> +<%def name="render_repository_type_select_field( repository_type_select_field, render_help=True )"> + <div class="form-row"> + <label>Repository type:</label> + <% + from tool_shed.repository_types import util + options = repository_type_select_field.options + repository_types = [] + for option_tup in options: + repository_types.append( option_tup[ 1 ] ) + render_as_text = len( options ) == 1 + if render_as_text: + repository_type = options[ 0 ][ 0 ] + %> + %if render_as_text: + ${repository_type | h} + %if render_help: + <div class="toolParamHelp" style="clear: both;"> + This repository's type cannot be changed because it's contents are valid only for it's current type or it has been cloned. + </div> + %endif + %else: + ${repository_type_select_field.get_html()} + %if render_help: + <div class="toolParamHelp" style="clear: both;"> + Select the repository type based on the following criteria. + <ul> + %if util.GENERIC in repository_types: + <li><b>Generic</b> - contents can be any set of valid Galaxy utilities + %endif + %if util.TOOL_DEPENDENCY_DEFINITION in repository_types: + <li><b>Tool dependency definition</b> - contents will always be restricted to one file named tool_dependencies.xml + %endif + </ul> + </div> + %endif + %endif + <div style="clear: both"></div> + </div> +</%def> + <%def name="render_sharable_str( repository, changeset_revision=None )"><% from tool_shed.util.shed_util_common import generate_sharable_link_for_repository_in_tool_shed diff -r 92225a7b6e5ecd87410f1da567b9e320b965be50 -r 5a41d725197d2d42475f80282a57b0b364898671 templates/webapps/tool_shed/repository/create_repository.mako --- a/templates/webapps/tool_shed/repository/create_repository.mako +++ b/templates/webapps/tool_shed/repository/create_repository.mako @@ -1,5 +1,6 @@ <%inherit file="/base.mako"/><%namespace file="/message.mako" import="render_msg" /> +<%namespace file="/webapps/tool_shed/repository/common.mako" import="render_repository_type_select_field" /><%def name="javascripts()"> ${parent.javascripts()} @@ -23,6 +24,7 @@ <input name="name" type="textfield" value="${name | h}" size="40"/><div style="clear: both"></div></div> + ${render_repository_type_select_field( repository_type_select_field, render_help=True )} <div class="form-row"><label>Synopsis:</label><input name="description" type="textfield" value="${description | h}" size="80"/> diff -r 92225a7b6e5ecd87410f1da567b9e320b965be50 -r 5a41d725197d2d42475f80282a57b0b364898671 templates/webapps/tool_shed/repository/manage_repository.mako --- a/templates/webapps/tool_shed/repository/manage_repository.mako +++ b/templates/webapps/tool_shed/repository/manage_repository.mako @@ -151,6 +151,7 @@ </div><div style="clear: both"></div></div> + ${render_repository_type_select_field( repository_type_select_field, render_help=True )} <div class="form-row"><label>Synopsis:</label><input name="description" type="textfield" value="${description | h}" size="80"/> diff -r 92225a7b6e5ecd87410f1da567b9e320b965be50 -r 5a41d725197d2d42475f80282a57b0b364898671 templates/webapps/tool_shed/repository/rate_repository.mako --- a/templates/webapps/tool_shed/repository/rate_repository.mako +++ b/templates/webapps/tool_shed/repository/rate_repository.mako @@ -44,6 +44,7 @@ ${render_clone_str( repository )} </div> %endif + ${render_repository_type_select_field( repository_type_select_field, render_help=False )} <div class="toolFormBody"><div class="form-row"><label>Description:</label> diff -r 92225a7b6e5ecd87410f1da567b9e320b965be50 -r 5a41d725197d2d42475f80282a57b0b364898671 templates/webapps/tool_shed/repository/view_repository.mako --- a/templates/webapps/tool_shed/repository/view_repository.mako +++ b/templates/webapps/tool_shed/repository/view_repository.mako @@ -100,6 +100,7 @@ ${repository.name | h} %endif </div> + ${render_repository_type_select_field( repository_type_select_field, render_help=False )} <div class="form-row"><label>Synopsis:</label> ${repository.description | h} 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.