def repository_list(self): """ Toolbox elements returned by api/tools may be of class ToolSection or Tool. Parse these accordingly to get a list of repositories. """ repositories = [] def record_repo(tool_elem): repo = get_repo_from_tool(tool_elem) if repo: repositories.append(repo) walk_tools(self.toolbox, record_repo) if self.get_data_managers: for tool in self.installed_tool_list: if tool.get("model_class") == 'DataManagerTool': repo = get_repo_from_tool(tool) if repo: repositories.append(repo) if self.get_all_tools: tools_with_panel = repositories[:] tsc = ToolShedClient(self.gi) repos = tsc.get_repositories() # Hereafter follows a gruesomely ineffecient algorithm. # The for loop and if statement are needed to retrieve tool_panel # section labels and ids. # If someone knows a more effecient way around this problem it # will be greatly appreciated. for repo in repos: if not repo['deleted']: tool_panel_section_id = None tool_panel_section_label = None for repo_with_panel in tools_with_panel: if the_same_repository(repo_with_panel, repo, check_revision=False): tool_panel_section_id = repo_with_panel.get('tool_panel_section_id') tool_panel_section_label = repo_with_panel.get('tool_panel_section_label') break repositories.append( dict(name=repo.get('name'), owner=repo.get('owner'), tool_shed_url=repo.get('tool_shed'), revisions=[repo.get('changeset_revision')], tool_panel_section_label=tool_panel_section_label, tool_panel_section_id=tool_panel_section_id) ) return repositories
def installed_repository_revisions(gi, omit=None): """ Get a list of repository revisions installed from a Tool Shed on a Galaxy instance. Included are all the repository revisions that were installed from a Tool Shed and are available from `/api/tool_shed_repositories` url on the given instance of Galaxy. :type gi: GalaxyInstance object :param gi: A GalaxyInstance object as retured by `galaxy_instance` method. :type omit: list of strings :param omit: A list of strings that, if found in a tool name, will result in the tool not being included in the returned list. :rtype: list of dicts :return: Each dict in the returned list will have the following keys: `name`, `owner`, `tool_shed_url`, `revisions`. .. seealso:: this method returns a subset of data returned by `installed_repositories` function """ if not omit: omit = [] tool_shed_client = ToolShedClient(gi) # Create dictionary to look up all tools based on repository information installed_revisions_list = [] installed_repositories_list = tool_shed_client.get_repositories() for installed_repository in installed_repositories_list: if installed_repository['status'] == 'Installed': skip = False # Check if we already processed this tool and, if so, add the new # revision to the existing list entry for installed_revision in installed_revisions_list: if the_same_repository(installed_repository, installed_revision): installed_revision['revisions'].append(installed_repository.get('changeset_revision', None)) skip = True # Check if the repo name is contained in the 'omit' list for omitted_repository in omit: if omitted_repository in installed_repository['name']: skip = True # We have not processed this tool so create a list entry if not skip: repo_info = { 'name': installed_repository['name'], 'owner': installed_repository['owner'], 'revisions': [installed_repository.get('changeset_revision', None)], 'tool_shed_url': 'https://' + installed_repository['tool_shed'], } installed_revisions_list.append(repo_info) return installed_revisions_list
class InstallRepositoryManager(object): """Manages the installation of new repositories on a galaxy instance""" def __init__(self, galaxy_instance): """Initialize a new tool manager""" self.gi = galaxy_instance self.tool_shed_client = ToolShedClient(self.gi) def installed_repositories(self): """Get currently installed tools""" return GiToToolYaml(gi=self.gi, skip_tool_panel_section_name=False, get_data_managers=True, get_all_tools=True).tool_list.get("tools") def filter_installed_repos(self, repos, check_revision=True): # TODO: Find a speedier algorithm. """This filters a list of repositories""" not_installed_repos = [] already_installed_repos = [] if check_revision: # If we want to check if revisions are equal, flatten the list, # so each repository - revision combination has its own entry installed_repos = flatten_repo_info(self.installed_repositories()) else: # If we do not care about revision equality, do not do the flatten # action to limit the number of comparisons. installed_repos = self.installed_repositories() for repo in repos: for installed_repo in installed_repos: if the_same_repository(installed_repo, repo, check_revision): already_installed_repos.append(repo) break else: # This executes when the for loop completes and no match has been found. not_installed_repos.append(repo) FilterResults = namedtuple( "FilterResults", ["not_installed_repos", "already_installed_repos"]) return FilterResults(already_installed_repos=already_installed_repos, not_installed_repos=not_installed_repos) def install_repositories( self, repositories, log=None, force_latest_revision=False, default_toolshed='https://toolshed.g2.bx.psu.edu/', default_install_tool_dependencies=False, default_install_resolver_dependencies=True, default_install_repository_dependencies=True): """Install a list of tools on the current galaxy""" if not repositories: raise ValueError("Empty list of tools was given") installation_start = dt.datetime.now() installed_repositories = [] skipped_repositories = [] errored_repositories = [] counter = 0 # Check repos for invalid keys for repo in repositories: for key in repo.keys(): if key not in VALID_KEYS and key != 'revisions': if log: log.warning( "'{0}' not a valid key. Will be skipped during parsing" .format(key)) # Start by flattening the repo list per revision flattened_repos = flatten_repo_info(repositories) total_num_repositories = len(flattened_repos) # Complete the repo information, and make sure each repository has a revision repository_list = [] for repository in flattened_repos: start = dt.datetime.now() try: complete_repo = complete_repo_information( repository, default_toolshed_url=default_toolshed, require_tool_panel_info=True, default_install_tool_dependencies= default_install_tool_dependencies, default_install_resolver_dependencies= default_install_resolver_dependencies, default_install_repository_dependencies= default_install_repository_dependencies, force_latest_revision=force_latest_revision) repository_list.append(complete_repo) except (LookupError, KeyError) as e: if log: log_repository_install_error(repository, start, str(e), log) errored_repositories.append(repository) # Filter out already installed repos filtered_repos = self.filter_installed_repos(repository_list) for skipped_repo in filtered_repos.already_installed_repos: counter += 1 if log: log_repository_install_skip(skipped_repo, counter, total_num_repositories, log) skipped_repositories.append(skipped_repo) # Install repos for repository in filtered_repos.not_installed_repos: counter += 1 if log: log_repository_install_start( repository, counter=counter, installation_start=installation_start, log=log, total_num_repositories=total_num_repositories) result = self.install_repository_revision(repository, log) if result == "error": errored_repositories.append(repository) elif result == "skipped": skipped_repositories.append(repository) elif result == "installed": installed_repositories.append(repository) # Log results if log: log.info("Installed repositories ({0}): {1}".format( len(installed_repositories), [(t['name'], t.get('changeset_revision')) for t in installed_repositories])) log.info("Skipped repositories ({0}): {1}".format( len(skipped_repositories), [(t['name'], t.get('changeset_revision')) for t in skipped_repositories])) log.info("Errored repositories ({0}): {1}".format( len(errored_repositories), [(t['name'], t.get('changeset_revision', "")) for t in errored_repositories])) log.info("All repositories have been installed.") log.info("Total run time: {0}".format(dt.datetime.now() - installation_start)) InstallResults = namedtuple("InstallResults", [ "installed_repositories", "errored_repositories", "skipped_repositories" ]) return InstallResults(installed_repositories=installed_repositories, skipped_repositories=skipped_repositories, errored_repositories=errored_repositories) def update_repositories(self, repositories=None, log=None, **kwargs): if not repositories: # Repositories None or empty list repositories = self.installed_repositories() else: filtered_repos = self.filter_installed_repos(repositories, check_revision=False) if filtered_repos.not_installed_repos: if log: log.warning( "The following tools are not installed and will not be upgraded: {0}" .format(filtered_repos.not_installed_repos)) repositories = filtered_repos.already_installed_repos return self.install_repositories(repositories, force_latest_revision=True, log=log, **kwargs) def test_tools(self, test_json, repositories=None, log=None, test_user_api_key=None, test_user="******"): """Run tool tests for all tools in each repository in supplied tool list or ``self.installed_repositories()``. """ tool_test_start = dt.datetime.now() tests_passed = [] test_exceptions = [] if not repositories: # If repositories is None or empty list # Consider a variant of this that doesn't even consume a tool list YAML? target # something like installed_repository_revisions(self.gi) repositories = self.installed_repositories() target_repositories = flatten_repo_info(repositories) installed_tools = [] for target_repository in target_repositories: repo_tools = tools_for_repository(self.gi, target_repository) installed_tools.extend(repo_tools) all_test_results = [] for tool in installed_tools: results = self._test_tool(tool, test_user, test_user_api_key) all_test_results.extend(results.tool_test_results) tests_passed.extend(results.tests_passed) test_exceptions.extend(results.test_exceptions) report_obj = { 'version': '0.1', 'tests': all_test_results, } with open(test_json, "w") as f: json.dump(report_obj, f) if log: log.info("Passed tool tests ({0}): {1}".format( len(tests_passed), [t for t in tests_passed])) log.info("Failed tool tests ({0}): {1}".format( len(test_exceptions), [t[0] for t in test_exceptions])) log.info("Total tool test time: {0}".format(dt.datetime.now() - tool_test_start)) def _test_tool(self, tool, test_user, test_user_api_key): if test_user_api_key is None: whoami = self.gi.make_get_request(self.gi.url + "/whoami").json() if whoami is not None: test_user_api_key = self.gi.key galaxy_interactor_kwds = { "galaxy_url": re.sub('/api', '', self.gi.url), "master_api_key": self.gi.key, "api_key": None, # TODO "keep_outputs_dir": '', } if test_user_api_key is None: galaxy_interactor_kwds["test_user"] = test_user galaxy_interactor = GalaxyInteractorApi(**galaxy_interactor_kwds) tool_id = tool["id"] tool_version = tool["version"] tool_test_dicts = galaxy_interactor.get_tool_tests( tool_id, tool_version=tool_version) test_indices = list(range(len(tool_test_dicts))) tool_test_results = [] tests_passed = [] test_exceptions = [] for test_index in test_indices: test_id = tool_id + "-" + str(test_index) def register(job_data): tool_test_results.append({ 'id': test_id, 'has_data': True, 'data': job_data, }) try: verify_tool(tool_id, galaxy_interactor, test_index=test_index, tool_version=tool_version, register_job_data=register, quiet=True) tests_passed.append(test_id) except Exception as e: test_exceptions.append((test_id, e)) Results = namedtuple( "Results", ["tool_test_results", "tests_passed", "test_exceptions"]) return Results(tool_test_results=tool_test_results, tests_passed=tests_passed, test_exceptions=test_exceptions) def install_repository_revision(self, repository, log): default_err_msg = ( 'All repositories that you are attempting to install ' 'have been previously installed.') start = dt.datetime.now() try: repository['new_tool_panel_section_label'] = repository.pop( 'tool_panel_section_label') response = self.tool_shed_client.install_repository_revision( **repository) if isinstance(response, dict) and response.get('status', None) == 'ok': # This rare case happens if a repository is already installed but # was not recognised as such in the above check. In such a # case the return value looks like this: # {u'status': u'ok', u'message': u'No repositories were # installed, possibly because the selected repository has # already been installed.'} if log: log.debug("\tRepository {0} is already installed.".format( repository['name'])) if log: log_repository_install_success(repository=repository, start=start, log=log) return "installed" except ConnectionError as e: if default_err_msg in e.body: # THIS SHOULD NOT HAPPEN DUE TO THE CHECKS EARLIER if log: log.debug( "\tRepository %s already installed (at revision %s)" % (repository['name'], repository['changeset_revision'])) return "skipped" elif "504" in str(e) or 'Connection aborted' in str(e): if log: log.debug( "Timeout during install of %s, extending wait to 1h", repository['name']) success = self.wait_for_install(repository=repository, log=log, timeout=3600) if success: if log: log_repository_install_success(repository=repository, start=start, log=log) return "installed" else: if log: log_repository_install_error(repository=repository, start=start, msg=e.body, log=log) return "error" else: if log: log_repository_install_error(repository=repository, start=start, msg=e.body, log=log) return "error" def wait_for_install(self, repository, log=None, timeout=3600): """ If nginx times out, we look into the list of installed repositories and try to determine if a repository of the same namer/owner is still installing. Returns True if install finished successfully, returns False when timeout is exceeded or installation has failed. """ start = dt.datetime.now() while (dt.datetime.now() - start) < dt.timedelta(seconds=timeout): try: installed_repo_list = self.tool_shed_client.get_repositories() for installing_repo in installed_repo_list: if (repository['name'] == installing_repo['name']) and ( installing_repo['owner'] == repository['owner']): if installing_repo['status'] == 'Installed': return True elif installing_repo['status'] == 'Error': return False else: time.sleep(10) except ConnectionError as e: if log: log.warning('Failed to get repositories list: %s', str(e)) time.sleep(10) return False
def __init__(self, galaxy_instance): """Initialize a new tool manager""" self.gi = galaxy_instance self.tool_shed_client = ToolShedClient(self.gi)
class InstallRepositoryManager(object): """Manages the installation of new repositories on a galaxy instance""" def __init__(self, galaxy_instance): """Initialize a new tool manager""" self.gi = galaxy_instance self.tool_shed_client = ToolShedClient(self.gi) def installed_repositories(self): """Get currently installed tools""" return GiToToolYaml(gi=self.gi, skip_tool_panel_section_name=False, get_data_managers=True, get_all_tools=True).tool_list.get("tools") def filter_installed_repos(self, repos, check_revision=True): # TODO: Find a speedier algorithm. """This filters a list of repositories""" not_installed_repos = [] already_installed_repos = [] if check_revision: # If we want to check if revisions are equal, flatten the list, # so each repository - revision combination has its own entry installed_repos = flatten_repo_info(self.installed_repositories()) else: # If we do not care about revision equality, do not do the flatten # action to limit the number of comparisons. installed_repos = self.installed_repositories() for repo in repos: for installed_repo in installed_repos: if the_same_repository(installed_repo, repo, check_revision): already_installed_repos.append(repo) break else: # This executes when the for loop completes and no match has been found. not_installed_repos.append(repo) FilterResults = namedtuple( "FilterResults", ["not_installed_repos", "already_installed_repos"]) return FilterResults(already_installed_repos=already_installed_repos, not_installed_repos=not_installed_repos) def install_repositories( self, repositories, log=None, force_latest_revision=False, default_toolshed='https://toolshed.g2.bx.psu.edu/', default_install_tool_dependencies=False, default_install_resolver_dependencies=True, default_install_repository_dependencies=True): """Install a list of tools on the current galaxy""" if not repositories: raise ValueError("Empty list of tools was given") installation_start = dt.datetime.now() installed_repositories = [] skipped_repositories = [] errored_repositories = [] counter = 0 # Check repos for invalid keys for repo in repositories: for key in repo.keys(): if key not in VALID_KEYS and key != 'revisions': if log: log.warning( "'{0}' not a valid key. Will be skipped during parsing" .format(key)) # Start by flattening the repo list per revision flattened_repos = flatten_repo_info(repositories) total_num_repositories = len(flattened_repos) # Complete the repo information, and make sure each repository has a revision repository_list = [] for repository in flattened_repos: start = dt.datetime.now() try: complete_repo = complete_repo_information( repository, default_toolshed_url=default_toolshed, require_tool_panel_info=True, default_install_tool_dependencies= default_install_tool_dependencies, default_install_resolver_dependencies= default_install_resolver_dependencies, default_install_repository_dependencies= default_install_repository_dependencies, force_latest_revision=force_latest_revision) repository_list.append(complete_repo) except Exception as e: # We'll run through the loop come whatever may, we log the errored repositories at the end anyway. if log: log_repository_install_error(repository, start, unicodify(e), log) errored_repositories.append(repository) # Filter out already installed repos filtered_repos = self.filter_installed_repos(repository_list) for skipped_repo in filtered_repos.already_installed_repos: counter += 1 if log: log_repository_install_skip(skipped_repo, counter, total_num_repositories, log) skipped_repositories.append(skipped_repo) # Install repos for repository in filtered_repos.not_installed_repos: counter += 1 if log: log_repository_install_start( repository, counter=counter, installation_start=installation_start, log=log, total_num_repositories=total_num_repositories) result = self.install_repository_revision(repository, log) if result == "error": errored_repositories.append(repository) elif result == "skipped": skipped_repositories.append(repository) elif result == "installed": installed_repositories.append(repository) # Log results if log: log.info("Installed repositories ({0}): {1}".format( len(installed_repositories), [(t['name'], t.get('changeset_revision')) for t in installed_repositories])) log.info("Skipped repositories ({0}): {1}".format( len(skipped_repositories), [(t['name'], t.get('changeset_revision')) for t in skipped_repositories])) log.info("Errored repositories ({0}): {1}".format( len(errored_repositories), [(t['name'], t.get('changeset_revision', "")) for t in errored_repositories])) log.info("All repositories have been installed.") log.info("Total run time: {0}".format(dt.datetime.now() - installation_start)) InstallResults = namedtuple("InstallResults", [ "installed_repositories", "errored_repositories", "skipped_repositories" ]) return InstallResults(installed_repositories=installed_repositories, skipped_repositories=skipped_repositories, errored_repositories=errored_repositories) def update_repositories(self, repositories=None, log=None, **kwargs): if not repositories: # Repositories None or empty list repositories = self.installed_repositories() else: filtered_repos = self.filter_installed_repos(repositories, check_revision=False) if filtered_repos.not_installed_repos: if log: log.warning( "The following tools are not installed and will not be upgraded: {0}" .format(filtered_repos.not_installed_repos)) repositories = filtered_repos.already_installed_repos return self.install_repositories(repositories, force_latest_revision=True, log=log, **kwargs) def test_tools( self, test_json, repositories=None, log=None, test_user_api_key=None, test_user="******", test_history_name=None, parallel_tests=1, test_all_versions=False, client_test_config_path=None, ): """Run tool tests for all tools in each repository in supplied tool list or ``self.installed_repositories()``. """ tool_test_start = dt.datetime.now() tests_passed = [] test_exceptions = [] if not repositories: # If repositories is None or empty list # Consider a variant of this that doesn't even consume a tool list YAML? target # something like installed_repository_revisions(self.gi) repositories = self.installed_repositories() target_repositories = flatten_repo_info(repositories) installed_tools = [] for target_repository in target_repositories: repo_tools = tools_for_repository(self.gi, target_repository, all_tools=test_all_versions) installed_tools.extend(repo_tools) all_test_results = [] galaxy_interactor = self._get_interactor(test_user, test_user_api_key) if client_test_config_path is not None: with open(client_test_config_path, "r") as f: client_test_config_dict = yaml.full_load(f) client_test_config = DictClientTestConfig( client_test_config_dict.get("tools")) else: client_test_config = None if test_history_name: for history in self.gi.histories.get_histories( name=test_history_name, deleted=False): test_history = history['id'] log.debug( "Using existing history with id '%s', last updated: %s", test_history, history['update_time']) break else: test_history = galaxy_interactor.new_history( history_name=test_history_name) else: test_history = galaxy_interactor.new_history() with ThreadPoolExecutor(max_workers=parallel_tests) as executor: try: for tool in installed_tools: self._test_tool( executor=executor, tool=tool, galaxy_interactor=galaxy_interactor, test_history=test_history, log=log, tool_test_results=all_test_results, tests_passed=tests_passed, test_exceptions=test_exceptions, client_test_config=client_test_config, ) finally: # Always write report, even if test was cancelled. try: executor.shutdown(wait=True) except KeyboardInterrupt: executor._threads.clear() thread._threads_queues.clear() n_passed = len(tests_passed) n_failed = len(test_exceptions) report_obj = { 'version': '0.1', 'suitename': 'Ephemeris tool tests targeting %s' % self.gi.base_url, 'results': { 'total': n_passed + n_failed, 'errors': n_failed, 'failures': 0, 'skips': 0, }, 'tests': sorted(all_test_results, key=lambda el: el['id']), } with open(test_json, "w") as f: json.dump(report_obj, f) if log: log.info("Report written to '%s'", os.path.abspath(test_json)) log.info("Passed tool tests ({0}): {1}".format( n_passed, [t for t in tests_passed])) log.info("Failed tool tests ({0}): {1}".format( n_failed, [t[0] for t in test_exceptions])) log.info( "Total tool test time: {0}".format(dt.datetime.now() - tool_test_start)) def _get_interactor(self, test_user, test_user_api_key): if test_user_api_key is None: whoami = self.gi.make_get_request(self.gi.url + "/whoami").json() if whoami is not None: test_user_api_key = self.gi.key galaxy_interactor_kwds = { "galaxy_url": re.sub('/api', '', self.gi.url), "master_api_key": self.gi.key, "api_key": test_user_api_key, # TODO "keep_outputs_dir": '', } if test_user_api_key is None: galaxy_interactor_kwds["test_user"] = test_user galaxy_interactor = GalaxyInteractorApi(**galaxy_interactor_kwds) return galaxy_interactor @staticmethod def _test_tool( executor, tool, galaxy_interactor, tool_test_results, tests_passed, test_exceptions, log, test_history=None, client_test_config=None, ): if test_history is None: test_history = galaxy_interactor.new_history() tool_id = tool["id"] tool_version = tool["version"] # If given a tool_id with a version suffix, strip it off so we can treat tool_version # correctly at least in client_test_config. if tool_version and tool_id.endswith("/" + tool_version): tool_id = tool_id[:-len("/" + tool_version)] label_base = tool_id if tool_version: label_base += "/" + str(tool_version) try: tool_test_dicts = galaxy_interactor.get_tool_tests( tool_id, tool_version=tool_version) except Exception as e: if log: log.warning("Fetching test definition for tool '%s' failed", label_base, exc_info=True) test_exceptions.append((label_base, e)) Results = namedtuple( "Results", ["tool_test_results", "tests_passed", "test_exceptions"]) return Results(tool_test_results=tool_test_results, tests_passed=tests_passed, test_exceptions=test_exceptions) test_indices = list(range(len(tool_test_dicts))) for test_index in test_indices: test_id = label_base + "-" + str(test_index) def run_test(index, test_id): def register(job_data): tool_test_results.append({ 'id': test_id, 'has_data': True, 'data': job_data, }) try: if log: log.info("Executing test '%s'", test_id) verify_tool( tool_id, galaxy_interactor, test_index=index, tool_version=tool_version, register_job_data=register, quiet=True, test_history=test_history, client_test_config=client_test_config, ) tests_passed.append(test_id) if log: log.info("Test '%s' passed", test_id) except Exception as e: if log: log.warning("Test '%s' failed", test_id, exc_info=True) test_exceptions.append((test_id, e)) executor.submit(run_test, test_index, test_id) def install_repository_revision(self, repository, log): default_err_msg = ( 'All repositories that you are attempting to install ' 'have been previously installed.') start = dt.datetime.now() try: repository['new_tool_panel_section_label'] = repository.pop( 'tool_panel_section_label') response = self.tool_shed_client.install_repository_revision( **repository) if isinstance(response, dict) and response.get('status', None) == 'ok': # This rare case happens if a repository is already installed but # was not recognised as such in the above check. In such a # case the return value looks like this: # {u'status': u'ok', u'message': u'No repositories were # installed, possibly because the selected repository has # already been installed.'} if log: log.debug("\tRepository {0} is already installed.".format( repository['name'])) if log: log_repository_install_success(repository=repository, start=start, log=log) return "installed" except (ConnectionError, requests.exceptions.ConnectionError) as e: if default_err_msg in unicodify(e): # THIS SHOULD NOT HAPPEN DUE TO THE CHECKS EARLIER if log: log.debug( "\tRepository %s already installed (at revision %s)" % (repository['name'], repository['changeset_revision'])) return "skipped" elif "504" in unicodify(e) or 'Connection aborted' in unicodify(e): if log: log.debug( "Timeout during install of %s, extending wait to 1h", repository['name']) success = self.wait_for_install(repository=repository, log=log, timeout=3600) if success: if log: log_repository_install_success(repository=repository, start=start, log=log) return "installed" else: if log: log_repository_install_error(repository=repository, start=start, msg=e.body, log=log) return "error" else: if log: log_repository_install_error(repository=repository, start=start, msg=e.body, log=log) return "error" def wait_for_install(self, repository, log=None, timeout=3600): """ If nginx times out, we look into the list of installed repositories and try to determine if a repository of the same namer/owner is still installing. Returns True if install finished successfully, returns False when timeout is exceeded or installation has failed. """ # We request a repository revision, but Galaxy may decide to install the next downloable revision. # This ensures we have a revision to track, and if not, finds the revision that is actually being installed name = repository['name'] owner = repository['owner'] changeset_revision = repository['changeset_revision'] installed_repos = self.tool_shed_client.get_repositories() filtered_repos = [ r for r in installed_repos if r['name'] == name and r['owner'] == owner ] assert filtered_repos, "Repository '%s' from owner '%s' not in list of repositories." % ( name, owner) # Check if exact repository revision in filtered_repos installing_repo_id = None for repo in filtered_repos: if repo['changeset_revision'] == changeset_revision: installing_repo_id = repo['id'] break else: # Galaxy may have decided to install a newer repository revision. We now try to guess which repository that is. non_terminal = [ r for r in filtered_repos if r['status'] in NON_TERMINAL_REPOSITORY_STATES ] if len(non_terminal) == 1: # Unambiguous, we wait for this repo installing_repo_id = non_terminal[0]['id'] elif len(filtered_repos) == 1: installing_repo_id = filtered_repos[0]['id'] else: # We may have a repo that is permanently in a non-terminal state (e.g because of restart during installation). # Raise an exception and continue with the remaining repos. msg = "Could not track repository for name '%s', owner '%s', revision '%s'. " msg += "Please uninstall all non-terminal repositories and ensure revision '%s' is installable." raise AssertionError( msg % (name, owner, changeset_revision, changeset_revision)) start = dt.datetime.now() while (dt.datetime.now() - start) < dt.timedelta(seconds=timeout): try: installed_repo = self.tool_shed_client.show_repository( installing_repo_id) status = installed_repo['status'] if status == 'Installed': return True elif status == 'Error': return False elif status in NON_TERMINAL_REPOSITORY_STATES: time.sleep(10) else: raise AssertionError( "Repository name '%s', owner '%s' in unknown status '%s'" % (name, owner, status)) except ConnectionError as e: if log: log.warning('Failed to get repositories list: %s', unicodify(e)) time.sleep(10) return False
def main(): parser = argparse.ArgumentParser(description='Rewrite arbitrarily many tool.yml files as one file per tool revision') parser.add_argument('-o', '--output_path', help='Output file path') # mandatory parser.add_argument('-f', '--files', help='Tool input files', nargs='+') # mandatory unless --update_existing is true parser.add_argument('-g', '--production_url', help='Galaxy server URL') parser.add_argument('-a', '--production_api_key', help='API key for galaxy server') parser.add_argument( '--update_existing', help='If there are several toolshed entries for one name or name/revision entry uninstall all of them', action='store_true', ) parser.add_argument('-s', '--source_directory', help='Directory containing tool yml files') args = parser.parse_args() files = args.files path = args.output_path update = args.update_existing source_dir = args.source_directory production_url = args.production_url production_api_key = args.production_api_key if not (files or source_dir): print('either --files or --source_directory must be defined as an argument\n') return elif files and source_dir: print('--files and --source_directory have both been provided. Ignoring source_directory in favour of files\n') if source_dir and not files: files = ['%s/%s' % (source_dir, name) for name in os.listdir(source_dir)] tools = [] for file in files: with open(file) as input: content = yaml.safe_load(input.read())['tools'] if isinstance(content, list): tools += content else: tools.append(content) if update: # update tools with trusted owners where updates are available if not production_url and production_api_key: raise Exception('--production_url and --production_api_key arguments are required when --update_exisiting flag is used') with open(trusted_owners_file) as infile: trusted_owners = yaml.safe_load(infile.read())['trusted_owners'] # load repository data to check which tools have updates available galaxy_instance = GalaxyInstance(production_url, production_api_key) toolshed_client = ToolShedClient(galaxy_instance) repos = toolshed_client.get_repositories() installed_repos = [r for r in repos if r['status'] == 'Installed'] # Skip deactivated repos trusted_tools = [t for t in tools if [o for o in trusted_owners if t['owner'] == o['owner']] != []] print('Checking for updates from %d tools' % len(trusted_tools)) tools = [] for i, tool in enumerate(trusted_tools): if i > 0 and i % 100 == 0: print('%d/%d' % (i, len(trusted_tools))) new_revision_info = get_new_revision(tool, installed_repos, trusted_owners) # if tool_has_new_revision(tool, installed_repos, trusted_owners): if new_revision_info: extraneous_keys = [key for key in tool.keys() if key not in ['name', 'owner', 'tool_panel_section_label', 'tool_shed_url']] for key in extraneous_keys: del tool[key] tool.update(new_revision_info) tools.append(tool) print('%d tools with updates available' % len(tools)) for tool in tools: if 'revisions' in tool.keys() and len(tool['revisions']) > 1: for rev in tool['revisions']: new_tool = tool new_tool['revisions'] = [rev] write_output_file(path=path, tool=new_tool) else: write_output_file(path=path, tool=tool)
counter = 1 total_num_tools = len(r_info) default_err_msg = 'All repositories that you are attempting to install have been previously installed.' for r in r_info: if 'install_tool_dependencies' not in r: r['install_tool_dependencies'] = True if 'install_repository_dependencies' not in r: r['install_repository_dependencies'] = True if 'tool_shed_url' not in r: r['tool_shed_url'] = 'http://toolshed.g2.bx.psu.edu' ts = ToolShedInstance(url=r['tool_shed_url']) if 'revision' not in r: r['revision'] = ts.repositories.get_ordered_installable_revisions( r['name'], r['owner'])[-1] tsc = ToolShedClient(gi) start = dt.datetime.now() print '\n(%s/%s) Installing tool %s from %s to section %s' % (counter, total_num_tools, r['name'], r['owner'], r['tool_panel_section_id']) response = tsc.install_repository_revision(r['tool_shed_url'], r['name'], r['owner'], r['revision'], r['install_tool_dependencies'], r['install_repository_dependencies'], r['tool_panel_section_id']) # new_tool_panel_section_label='API tests') end = dt.datetime.now() if 'error' in response: if response['error'] == default_err_msg: print "Tool %s already installed (at revision %s)" % (r['name'], r['revision']) else: print ("Tool install error! Name: %s, owner: %s, revision: %s, error: %s" % (r['name'], r['owner'], r['revision'], response['error'])) else: