def test_install(galaxy_context, mocker): repo_spec = RepositorySpec(namespace='some_namespace', name='some_name', version='4.3.2') mock_fetcher = mocker.MagicMock(name='MockFetch') fetch_results = {'archive_path': '/dev/null/doesntexist'} # Mock args for creating a Mock to replace repository_archive.load_archive # TODO: the 'config' constructor can be replaced with straight mocker.patch? config = {'return_value': mocker.MagicMock(name='MockRepoArchive')} mocker.patch.object(install.repository_archive, 'load_archive', **config) res = install.install(galaxy_context, fetcher=mock_fetcher, fetch_results=fetch_results, repository_spec=repo_spec, display_callback=display_callback) log.debug('res: %s', res) assert isinstance(res, list) assert len(res) > 0 assert isinstance(res[0], Repository) assert res[0].repository_spec == repo_spec assert galaxy_context.content_path in res[0].path
def test_install_no_valid_content(galaxy_context, mocker): repo_spec = RepositorySpec(namespace='some_namespace', name='some_name', version='4.3.2') mock_fetcher = mocker.MagicMock(name='MockFetch') fetch_results = {} with pytest.raises(exceptions.GalaxyClientError, match='No valid content data found for') as exc_info: install.install(galaxy_context, fetcher=mock_fetcher, fetch_results=fetch_results, repository_spec=repo_spec, display_callback=display_callback) log.debug('exc_info: %s', exc_info)
def install_repository(galaxy_context, requirement_to_install, display_callback=None, # TODO: error handling callback ? ignore_errors=False, no_deps=False, force_overwrite=False): '''This installs a single package by finding it, fetching it, verifying it and installing it.''' display_callback = display_callback or display.display_callback # INITIAL state # dep_requirements = [] # TODO: we could do all the downloads first, then install them. Likely # less error prone mid 'transaction' log.debug('Processing %r', requirement_to_install) repository_spec_to_install = requirement_to_install.requirement_spec requirement_spec_to_install = requirement_to_install.requirement_spec # else trans to ... FIND_FETCHER? # TODO: check if already installed and move to approriate state log.debug('About to find() requested requirement_spec_to_install: %s', requirement_spec_to_install) display_callback('', level='info') display_callback('Installing spec: %s' % requirement_spec_to_install.label, level='info') # We dont have anything that matches the RequirementSpec installed fetcher = fetch_factory.get(galaxy_context=galaxy_context, requirement_spec=requirement_spec_to_install) # if we fail to get a fetcher here, then to... FIND_FETCHER_FAILURE ? # could also move some of the logic in fetcher_factory to be driven from here # and make the steps of mapping repository spec -> fetcher method part of the # state machine. That might be a good place to support multiple galaxy servers # or preferring local content to remote content, etc. # FIND state # See if we can find metadata and/or download the archive before we try to # remove an installed version... try: find_results = install.find(fetcher) except exceptions.GalaxyError as e: log.debug('requirement_to_install %s failed to be met: %s', requirement_to_install, e) log.warning('Unable to find metadata for %s: %s', requirement_spec_to_install.label, e) # FIXME: raise dep error exception? raise_without_ignore(ignore_errors, e) # continue return None # TODO: make sure repository_spec version is correct and set # TODO: state transition, if find_results -> INSTALL # if not, then FIND_FAILED # TODO/FIXME: We give find() a RequirementSpec, but find_results should have enough # info to create a concrete RepositorySpec # TODO: if we want client side content whitelist/blacklist, or pinned versions, # or rules to only update within some semver range (ie, only 'patch' level), # we could hook rule validation stuff here. # TODO: build a new repository_spec based on what we actually fetched to feed to # install etc. The fetcher.fetch() could return a datastructure needed to build # the new one instead of doing it in verify() found_repository_spec = install.repository_spec_from_find_results(find_results, requirement_spec_to_install) log.debug('found_repository_spec: %s', found_repository_spec) display_callback(' Found: %s (for spec %s)' % (found_repository_spec, requirement_spec_to_install.label)) # See if the found collection spec is already installed and either warn or 'force_overwrite' # to remove existing first. # cheap 'update' is to consider anything already installed that matches the request repo_spec # as 'installed' and let force override that. # potential_repository_spec is a repo spec for the install candidate we potentially found. irdb = installed_repository_db.InstalledRepositoryDatabase(galaxy_context) # log.debug('Checking to see if %s is already installed', requirement_spec_to_install) log.debug('Checking to see if a collection named %s is already installed', found_repository_spec.label) repository_spec_match_filter = matchers.MatchRepositorySpecNamespaceName([found_repository_spec]) # already_installed_iter = irdb.by_requirement_spec(requirement_spec_to_install) already_installed_iter = irdb.select(repository_spec_match_filter=repository_spec_match_filter) already_installed = sorted(list(already_installed_iter)) log.debug('already_installed: %s', already_installed) # TODO: The already installed check above verifies that nothing that matches the requirement spec is installed, # but just because the name+version required wasn't installed, that doesn't mean that name at a different # version isn't installed. # To catch that, also need to check if the irdb by name to see if anything with that name is installed. # repository_spec_to_install = found_repository_spec log.debug('About to download repository requested by %s: %s', requirement_spec_to_install, repository_spec_to_install) if find_results['custom'].get('collection_is_deprecated', False): display_callback("The collection '%s' is deprecated." % (found_repository_spec.label), level='warning') # FETCH state try: fetch_results = install.fetch(fetcher, repository_spec=repository_spec_to_install, find_results=find_results) log.debug('fetch_results: %s', fetch_results) # fetch_results will include a 'archive_path' pointing to where the artifact # was saved to locally. except exceptions.GalaxyError as e: # fetch error probably should just go to a FAILED state, at least until # we have to implement retries log.warning('Unable to fetch %s: %s', repository_spec_to_install.name, e) raise_without_ignore(ignore_errors, e) # continue # FIXME: raise ? return None # FIXME: seems like we want to resolve deps before trying install # We need the role (or other content) deps from meta before installing # though, and sometimes (for galaxy case) we dont know that until we've downloaded # the file, which we dont do until somewhere in the begin of content.install (fetch). # We can get that from the galaxy API though. # # FIXME: exc handling # Remove the already installed version, via --force for already_installed_repository in already_installed: repo_label = '%s,%s' % (already_installed_repository.repository_spec.label, already_installed_repository.repository_spec.version) # bail if we are not overwriting already installed content if not force_overwrite: display_callback(' %s is already installed at %s' % (repo_label, already_installed_repository.path), level='warning') log.debug('A collection providing %s was already installed. In %s', requirement_spec_to_install, already_installed) return None display_callback(' Removing: %s (previously installed to %s)' % (repo_label, already_installed_repository.path), level='info') log.debug('Removing already_installed %s', already_installed_repository) repository.remove(already_installed_repository) installed_repositories = [] try: installed_repositories = install.install(galaxy_context, fetcher, fetch_results, repository_spec=found_repository_spec, force_overwrite=force_overwrite, display_callback=display_callback) except exceptions.GalaxyError as e: msg = "- %s was NOT installed successfully: %s " display_callback(msg % (found_repository_spec, e), level='warning') log.warning(msg, found_repository_spec.label, str(e)) raise_without_ignore(ignore_errors, e) return [] if not installed_repositories: log.warning("- %s was NOT installed successfully.", found_repository_spec.label) raise_without_ignore(ignore_errors) return installed_repositories
def install_repository( galaxy_context, requirement_to_install, display_callback=None, # TODO: error handling callback ? ignore_errors=False, no_deps=False, force_overwrite=False): '''This installs a single package by finding it, fetching it, verifying it and installing it.''' display_callback = display_callback or display.display_callback # INITIAL state # dep_requirements = [] # TODO: we could do all the downloads first, then install them. Likely # less error prone mid 'transaction' log.debug('Processing %s', requirement_to_install) repository_spec_to_install = requirement_to_install.requirement_spec # else trans to ... FIND_FETCHER? # TODO: check if already installed and move to approriate state log.debug('About to find() requested repository_spec_to_install: %s', repository_spec_to_install) # potential_repository_spec is a repo spec for the install candidate we potentially found. irdb = installed_repository_db.InstalledRepositoryDatabase(galaxy_context) log.debug('Checking to see if %s is already installed', repository_spec_to_install) already_installed_iter = irdb.by_repository_spec( repository_spec_to_install) already_installed = sorted(list(already_installed_iter)) log.debug('already_installed: %s', already_installed) if already_installed: for already_installed_repository in already_installed: display_callback( '%s is already installed at %s' % (already_installed_repository.repository_spec.label, already_installed_repository.path), level='warning') log.debug('Stuff %s was already installed. In %s', repository_spec_to_install, already_installed) return None fetcher = fetch_factory.get(galaxy_context=galaxy_context, repository_spec=repository_spec_to_install) # if we fail to get a fetcher here, then to... FIND_FETCHER_FAILURE ? # could also move some of the logic in fetcher_factory to be driven from here # and make the steps of mapping repository spec -> fetcher method part of the # state machine. That might be a good place to support multiple galaxy servers # or preferring local content to remote content, etc. # FIND state # See if we can find metadata and/or download the archive before we try to # remove an installed version... try: find_results = install.find(fetcher) except exceptions.GalaxyError as e: log.warning('Unable to find metadata for %s: %s', repository_spec_to_install.label, e) # FIXME: raise dep error exception? raise_without_ignore(ignore_errors, e) # continue return None # TODO: make sure repository_spec version is correct and set # TODO: state transition, if find_results -> INSTALL # if not, then FIND_FAILED log.debug('About to download requested repository_spec_to_install: %s', repository_spec_to_install) # FETCH state try: fetch_results = install.fetch( fetcher, repository_spec=repository_spec_to_install, find_results=find_results) log.debug('fetch_results: %s', fetch_results) # fetch_results will include a 'archive_path' pointing to where the artifact # was saved to locally. except exceptions.GalaxyError as e: # fetch error probably should just go to a FAILED state, at least until # we have to implement retries log.warning('Unable to fetch %s: %s', repository_spec_to_install.name, e) raise_without_ignore(ignore_errors, e) # continue # FIXME: raise ? return None # TODO: if we want client side content whitelist/blacklist, or pinned versions, # or rules to only update within some semver range (ie, only 'patch' level), # we could hook rule validation stuff here. # TODO: build a new repository_spec based on what we actually fetched to feed to # install etc. The fetcher.fetch() could return a datastructure needed to build # the new one instead of doing it in verify() fetched_repository_spec = install.update_repository_spec( fetch_results, repository_spec_to_install) log.debug('fetched_repository_spec: %s', fetched_repository_spec) # FIXME: seems like we want to resolve deps before trying install # We need the role (or other content) deps from meta before installing # though, and sometimes (for galaxy case) we dont know that until we've downloaded # the file, which we dont do until somewhere in the begin of content.install (fetch). # We can get that from the galaxy API though. # # FIXME: exc handling installed_repositories = [] try: installed_repositories = install.install( galaxy_context, fetcher, fetch_results, repository_spec=fetched_repository_spec, force_overwrite=force_overwrite, display_callback=display_callback) except exceptions.GalaxyError as e: msg = "- %s was NOT installed successfully: %s " display_callback(msg % (fetched_repository_spec.label, e), level='warning') log.warning(msg, fetched_repository_spec.label, str(e)) raise_without_ignore(ignore_errors, e) return [] if not installed_repositories: log.warning("- %s was NOT installed successfully.", fetched_repository_spec.label) raise_without_ignore(ignore_errors) return installed_repositories