""" Implementation of `GitRepositoryAdapter`, adapter that is used to handle git repositories """ import glob import os from .adapter import Adapter # pylint: disable=relative-import def _get_filenames(path): return [os.path.split(topic)[1] for topic in glob.glob(path)] class RepositoryAdapter(Adapter): """ Implements methods needed to handle standard repository based adapters. """ def _get_list(self, prefix=None): """ List of files in the cheat sheets directory with the extension removed """ answer = _get_filenames( os.path.join( self.local_repository_location(), self._cheatsheet_files_prefix, "*" + self._cheatsheet_files_extension, ) ) ext = self._cheatsheet_files_extension if ext: answer = [ filename[: -len(ext)] for filename in answer if filename.endswith(ext) ] return answer def _get_page(self, topic, request_options=None): filename = os.path.join( self.local_repository_location(), self._cheatsheet_files_prefix, topic ) if os.path.exists(filename) and not os.path.isdir(filename): answer = self._format_page(open(filename, "r").read()) else: # though it should not happen answer = "%s:%s not found" % (str(self.__class__), topic) return answer class GitRepositoryAdapter(RepositoryAdapter): # pylint: disable=abstract-method """ Implements all methods needed to handle cache handling for git-repository-based adapters """ @classmethod def fetch_command(cls): """ Initial fetch of the repository. Return cmdline that has to be executed to fetch the repository. Skipping if `self._repository_url` is not specified """ if not cls._repository_url: return None if not cls._repository_url.startswith("https://github.com/"): # in this case `fetch` has to be implemented # in the distinct adapter subclass raise RuntimeError( "Do not known how to handle this repository: %s" % cls._repository_url ) local_repository_dir = cls.local_repository_location() if not local_repository_dir: return None return ["git", "clone", "--depth=1", cls._repository_url, local_repository_dir] @classmethod def update_command(cls): """ Update of the repository. Return cmdline that has to be executed to update the repository inside `local_repository_location()`. """ if not cls._repository_url: return None local_repository_dir = cls.local_repository_location() if not local_repository_dir: return None if not cls._repository_url.startswith("https://github.com/"): # in this case `update` has to be implemented # in the distinct adapter subclass raise RuntimeError( "Do not known how to handle this repository: %s" % cls._repository_url ) return ["git", "pull"] @classmethod def current_state_command(cls): """ Get current state of repository (current revision). This is used to find what cache entries should be invalidated. """ if not cls._repository_url: return None local_repository_dir = cls.local_repository_location() if not local_repository_dir: return None if not cls._repository_url.startswith("https://github.com/"): # in this case `update` has to be implemented # in the distinct adapter subclass raise RuntimeError( "Do not known how to handle this repository: %s" % cls._repository_url ) return ["git", "rev-parse", "--short", "HEAD", "--"] @classmethod def save_state(cls, state): """ Save state `state` of the repository. Must be called after the cache clean up. """ local_repository_dir = cls.local_repository_location() state_filename = os.path.join(local_repository_dir, ".cached_revision") open(state_filename, "wb").write(state) @classmethod def get_state(cls): """ Return the saved `state` of the repository. If state cannot be read, return None """ local_repository_dir = cls.local_repository_location() state_filename = os.path.join(local_repository_dir, ".cached_revision") state = None if os.path.exists(state_filename): state = open(state_filename, "r").read() return state @classmethod def get_updates_list_command(cls): """ Return list of updates since the last update whose id is saved as the repository state. The list is used to invalidate the cache. """ current_state = cls.get_state() if not current_state: return ["git", "ls-tree", "--full-tree", "-r", "--name-only", "HEAD", "--"] return ["git", "diff", "--name-only", current_state, "HEAD", "--"]