def get_required_repo_info_dicts(self, tool_shed_url, repo_info_dicts): """ Inspect the list of repo_info_dicts for repository dependencies and append a repo_info_dict for each of them to the list. All repository_dependency entries in each of the received repo_info_dicts includes all required repositories, so only one pass through this method is required to retrieve all repository dependencies. """ all_required_repo_info_dict = {} all_repo_info_dicts = [] if repo_info_dicts: # We'll send tuples of ( tool_shed, repository_name, repository_owner, changeset_revision ) to the tool # shed to discover repository ids. required_repository_tups = [] for repo_info_dict in repo_info_dicts: if repo_info_dict not in all_repo_info_dicts: all_repo_info_dicts.append(repo_info_dict) for repository_name, repo_info_tup in repo_info_dict.items(): description, \ repository_clone_url, \ changeset_revision, \ ctx_rev, \ repository_owner, \ repository_dependencies, \ tool_dependencies = \ repository_util.get_repo_info_tuple_contents(repo_info_tup) if repository_dependencies: for key, val in repository_dependencies.items(): if key in ['root_key', 'description']: continue repository_components_tuple = get_components_from_key( key) components_list = repository_util.extract_components_from_tuple( repository_components_tuple) # 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. # For backward compatibility to the 12/20/12 Galaxy release. only_if_compiling_contained_td = 'False' if len(components_list) == 4: only_if_compiling_contained_td = 'False' elif len(components_list) == 5: only_if_compiling_contained_td = 'False' if not asbool(only_if_compiling_contained_td): if components_list not in required_repository_tups: required_repository_tups.append( components_list) for components_list in val: try: only_if_compiling_contained_td = components_list[ 5] except IndexError: 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 (see above comment). if not asbool(only_if_compiling_contained_td): if components_list not in required_repository_tups: required_repository_tups.append( components_list) else: # We have a single repository with no dependencies. components_list = [ tool_shed_url, repository_name, repository_owner, changeset_revision ] required_repository_tups.append(components_list) if required_repository_tups: # The value of required_repository_tups is a list of tuples, so we need to encode it. encoded_required_repository_tups = [] for required_repository_tup in required_repository_tups: # Convert every item in required_repository_tup to a string. required_repository_tup = [ str(item) for item in required_repository_tup ] encoded_required_repository_tups.append( encoding_util.encoding_sep.join( required_repository_tup)) encoded_required_repository_str = encoding_util.encoding_sep2.join( encoded_required_repository_tups) encoded_required_repository_str = encoding_util.tool_shed_encode( encoded_required_repository_str) if repository_util.is_tool_shed_client(self.app): # Handle secure / insecure Tool Shed URL protocol changes and port changes. tool_shed_url = common_util.get_tool_shed_url_from_tool_shed_registry( self.app, tool_shed_url) pathspec = ['repository', 'get_required_repo_info_dict'] url = build_url(tool_shed_url, pathspec=pathspec) # Fix for handling 307 redirect not being handled nicely by urlopen() when the Request() has data provided try: url = _urlopen(url).geturl() except HTTPError as e: if e.code == 502: pass else: raise payload = urlencode( dict(encoded_str=encoded_required_repository_str)) response = _urlopen(url, payload).read() if response: try: required_repo_info_dict = json.loads( unicodify(response)) except Exception as e: log.exception(e) return all_repo_info_dicts required_repo_info_dicts = [] for k, v in required_repo_info_dict.items(): if k == 'repo_info_dicts': encoded_dict_strings = required_repo_info_dict[ 'repo_info_dicts'] for encoded_dict_str in encoded_dict_strings: decoded_dict = encoding_util.tool_shed_decode( encoded_dict_str) required_repo_info_dicts.append( decoded_dict) else: if k not in all_required_repo_info_dict: all_required_repo_info_dict[k] = v else: if v and not all_required_repo_info_dict[k]: all_required_repo_info_dict[k] = v if required_repo_info_dicts: for required_repo_info_dict in required_repo_info_dicts: # Each required_repo_info_dict has a single entry, and all_repo_info_dicts is a list # of dictionaries, each of which has a single entry. We'll check keys here rather than # the entire dictionary because a dictionary entry in all_repo_info_dicts will include # lists of discovered repository dependencies, but these lists will be empty in the # required_repo_info_dict since dependency discovery has not yet been performed for these # dictionaries. required_repo_info_dict_key = next( iter(required_repo_info_dict)) all_repo_info_dicts_keys = [ next(iter(d)) for d in all_repo_info_dicts ] if required_repo_info_dict_key not in all_repo_info_dicts_keys: all_repo_info_dicts.append( required_repo_info_dict) else: # required_repo_info_dict_key corresponds to the repo name. # A single install transaction might require the installation of 2 or more repos # with the same repo name but different owners or versions. # Therefore, if required_repo_info_dict_key is already in all_repo_info_dicts, # check that the tool id is already present. If it is not, we are dealing with the same repo name, # but a different owner/changeset revision or version and we add the repo to the list of repos to be installed. tool_id = required_repo_info_dict[ required_repo_info_dict_key][1] is_present = False for repo_info_dict in all_repo_info_dicts: for k, v in repo_info_dict.items(): if required_repo_info_dict_key == k: if tool_id == v[1]: is_present = True break if not is_present: all_repo_info_dicts.append( required_repo_info_dict) all_required_repo_info_dict[ 'all_repo_info_dicts'] = all_repo_info_dicts return all_required_repo_info_dict
def build_repository_dependency_relationships(self, repo_info_dicts, tool_shed_repositories): """ Build relationships between installed tool shed repositories and other installed tool shed repositories upon which they depend. These relationships are defined in the repository_dependencies entry for each dictionary in the received list of repo_info_dicts. Each of these dictionaries is associated with a repository in the received tool_shed_repositories list. """ install_model = self.app.install_model log.debug("Building repository dependency relationships...") for repo_info_dict in repo_info_dicts: for name, repo_info_tuple in repo_info_dict.items(): description, \ repository_clone_url, \ changeset_revision, \ ctx_rev, \ repository_owner, \ repository_dependencies, \ tool_dependencies = \ repository_util.get_repo_info_tuple_contents(repo_info_tuple) if repository_dependencies: for key, val in repository_dependencies.items(): if key in ['root_key', 'description']: continue d_repository = None repository_components_tuple = get_components_from_key( key) components_list = repository_util.extract_components_from_tuple( repository_components_tuple) d_toolshed, d_name, d_owner, d_changeset_revision = components_list[ 0:4] for tsr in tool_shed_repositories: # Get the the tool_shed_repository defined by name, owner and changeset_revision. This is # the repository that will be dependent upon each of the tool shed repositories contained in # val. We'll need to check tool_shed_repository.tool_shed as well if/when repository dependencies # across tool sheds is supported. if tsr.name == d_name and tsr.owner == d_owner and tsr.changeset_revision == d_changeset_revision: d_repository = tsr break if d_repository is None: # The dependent repository is not in the received list so look in the database. d_repository = self.get_or_create_tool_shed_repository( d_toolshed, d_name, d_owner, d_changeset_revision) # Process each repository_dependency defined for the current dependent repository. for repository_dependency_components_list in val: required_repository = None rd_toolshed, \ rd_name, \ rd_owner, \ rd_changeset_revision, \ rd_prior_installation_required, \ rd_only_if_compiling_contained_td = \ common_util.parse_repository_dependency_tuple(repository_dependency_components_list) # Get the the tool_shed_repository defined by rd_name, rd_owner and rd_changeset_revision. This # is the repository that will be required by the current d_repository. # TODO: Check tool_shed_repository.tool_shed as well when repository dependencies across tool sheds is supported. for tsr in tool_shed_repositories: if tsr.name == rd_name and tsr.owner == rd_owner and tsr.changeset_revision == rd_changeset_revision: required_repository = tsr break if required_repository is None: # The required repository is not in the received list so look in the database. required_repository = self.get_or_create_tool_shed_repository( rd_toolshed, rd_name, rd_owner, rd_changeset_revision) # Ensure there is a repository_dependency relationship between d_repository and required_repository. rrda = None for rd in d_repository.repository_dependencies: if rd.id == required_repository.id: rrda = rd break if not rrda: # Make sure required_repository is in the repository_dependency table. repository_dependency = self.get_repository_dependency_by_repository_id( install_model, required_repository.id) if not repository_dependency: log.debug( 'Creating new repository_dependency record for installed revision %s of repository: %s owned by %s.', required_repository. installed_changeset_revision, required_repository.name, required_repository.owner) repository_dependency = install_model.RepositoryDependency( tool_shed_repository_id= required_repository.id) install_model.context.add( repository_dependency) install_model.context.flush() # Build the relationship between the d_repository and the required_repository. rrda = install_model.RepositoryRepositoryDependencyAssociation( tool_shed_repository_id=d_repository.id, repository_dependency_id= repository_dependency.id) install_model.context.add(rrda) install_model.context.flush()