import re from ..clients.github_client import GitHubClient from ..downloaders.downloader_exception import DownloaderException from ..clients.client_exception import ClientException from .provider_exception import ProviderException class GitHubUserProvider(): """ Allows using a GitHub user/organization as the source for multiple packages, or in Package Control terminology, a "repository". :param repo: The public web URL to the GitHub user/org. Should be in the format `https://github.com/user`. :param settings: A dict containing at least the following fields: `cache_length`, `debug`, `timeout`, `user_agent`, Optional fields: `http_proxy`, `https_proxy`, `proxy_username`, `proxy_password`, `query_string_params` `install_prereleases` """ def __init__(self, repo, settings): self.cache = {} self.repo = repo self.settings = settings self.failed_sources = {} @classmethod def match_url(cls, repo): """Indicates if this provider can handle the provided repo""" return re.search('^https?://github.com/[^/]+/?$', repo) != None def prefetch(self): """ Go out and perform HTTP operations, caching the result """ [name for name, info in self.get_packages()] def get_failed_sources(self): """ List of any URLs that could not be accessed while accessing this repository :raises: DownloaderException: when there is an issue download package info ClientException: when there is an issue parsing package info :return: A generator of ("https://github.com/user/repo", Exception()) tuples """ return self.failed_sources.items() def get_broken_packages(self): """ For API-compatibility with RepositoryProvider """ return {}.items() def get_packages(self, invalid_sources=None): """ Uses the GitHub API to construct necessary info for all packages :param invalid_sources: A list of URLs that should be ignored :raises: DownloaderException: when there is an issue download package info ClientException: when there is an issue parsing package info :return: A generator of ( 'Package Name', { 'name': name, 'description': description, 'author': author, 'homepage': homepage, 'last_modified': last modified date, 'download': { 'url': url, 'date': date, 'version': version }, 'previous_names': [], 'labels': [], 'sources': [the user URL], 'readme': url, 'issues': url, 'donate': url, 'buy': None } ) tuples """ if 'get_packages' in self.cache: for key, value in self.cache['get_packages'].items(): yield (key, value) return client = GitHubClient(self.settings) if invalid_sources != None and self.repo in invalid_sources: raise StopIteration() try: user_repos = client.user_info(self.repo) except (DownloaderException, ClientException, ProviderException) as e: self.failed_sources = [self.repo] self.cache['get_packages'] = e raise e output = {} for repo_info in user_repos: try: name = repo_info['name'] repo_url = 'https://github.com/' + repo_info['user_repo'] download = client.download_info(repo_url) details = { 'name': name, 'description': repo_info['description'], 'homepage': repo_info['homepage'], 'author': repo_info['author'], 'last_modified': download.get('date'), 'download': download, 'previous_names': [], 'labels': [], 'sources': [self.repo], 'readme': repo_info['readme'], 'issues': repo_info['issues'], 'donate': repo_info['donate'], 'buy': None } output[name] = details yield (name, details) except (DownloaderException, ClientException, ProviderException) as e: self.failed_sources[repo_url] = e self.cache['get_packages'] = output def get_renamed_packages(self): """For API-compatibility with RepositoryProvider""" return {} def get_unavailable_packages(self): """ Method for compatibility with RepositoryProvider class. These providers are based on API calls, and thus do not support different platform downloads, making it impossible for there to be unavailable packages. :return: An empty list """ return []