import os from dulwich.client import get_transport_and_path from dulwich.errors import UpdateRefsError, SendPackError from dulwich.refs import SYMREF from dulwich.repo import Repo from twisted.python import log LOCAL_BRANCH_PREFIX = 'refs/heads/' REMOTE_BRANCH_PREFIX = 'refs/remotes/' class GitRepo(object): """ Simple high-level wrapper for dulwich. """ def __init__(self, repo): self.path = repo self.repo = Repo(repo) def stage(self, filenames): paths = [os.path.relpath(filename, self.path) for filename in filenames] log.msg('Staging: %s' % ', '.join(paths), system='git') self.repo.stage(paths) def has_changed(self): head = self.repo.object_store[self.repo.head()] index = self.repo.open_index() if any(index.changes_from_tree(self.repo.object_store, head.tree)): return True log.msg('No changes', system='git') return False def commit(self, message, committer): log.msg('Committing: %s' % message, system='git') self.repo.do_commit(message, committer=committer) def _get_git_remote_url(self, remote_name): try: config = self.repo.get_config() return config.get(("remote", remote_name), "url") except KeyError: pass return None def _get_git_branch(self): contents = self.repo.refs.read_ref('HEAD') if not contents.startswith(SYMREF): return None refname = contents[len(SYMREF):] if refname.startswith(LOCAL_BRANCH_PREFIX): return refname[len(LOCAL_BRANCH_PREFIX):] return refname def push(self, remote): remote_location = self._get_git_remote_url(remote) if remote_location is not None: branch = self._get_git_branch() local_ref = '%s%s' % (LOCAL_BRANCH_PREFIX, branch) log.msg('Pushing %s to %s' % (branch, remote_location), system='git') def update_refs(refs): refs[local_ref] = self.repo.refs['HEAD'] return refs client, path = get_transport_and_path(remote_location) try: new_refs = client.send_pack( path, update_refs, self.repo.object_store.generate_pack_contents) # update remote refs if local_ref in new_refs: remote_ref = '%s%s/%s' % (REMOTE_BRANCH_PREFIX, remote, branch) self.repo.refs[remote_ref] = new_refs[local_ref] except (UpdateRefsError, SendPackError) as e: log.err(e, system='git') else: log.msg('Not pushing, origin remote not found', system='git')