import os import re import lxml.html import ghdiff import gittle.utils from gittle import Gittle from dulwich.repo import NotGitRepository from werkzeug.utils import escape, unescape from util import to_canonical from realms.models import Site class MyGittle(Gittle): def file_history(self, path): """Returns all commits where given file was modified """ versions = [] commits_info = self.commit_info() seen_shas = set() for commit in commits_info: try: files = self.get_commit_files(commit['sha'], paths=[path]) file_path, file_data = files.items()[0] except IndexError: continue file_sha = file_data['sha'] if file_sha in seen_shas: continue else: seen_shas.add(file_sha) versions.append(dict(author=commit['author']['name'], time=commit['time'], file_sha=file_sha, sha=commit['sha'], message=commit['message'])) return versions def mv_fs(self, file_pair): old_name, new_name = file_pair os.rename(self.path + "/" + old_name, self.path + "/" + new_name) class Wiki(): path = None base_path = '/' default_ref = 'master' default_committer_name = 'Anon' default_committer_email = 'anon@anon.anon' index_page = 'home' repo = None def __init__(self, path): try: self.repo = MyGittle(path) except NotGitRepository: self.repo = MyGittle.init(path) self.path = path @staticmethod def is_registered(name): s = Site() return True if s.get_by_name(name) else False def revert_page(self, name, commit_sha, message, username): page = self.get_page(name, commit_sha) if not page: # Page not found return None commit_info = gittle.utils.git.commit_info(self.repo[commit_sha]) message = commit_info['message'] return self.write_page(name, page['data'], message=message, username=username) def write_page(self, name, content, message=None, create=False, username=None, email=None): def escape_repl(m): if m.group(1): return "```" + escape(m.group(1)) + "```" def unescape_repl(m): if m.group(1): return "```" + unescape(m.group(1)) + "```" # prevents p tag from being added, we remove this later content = '
' + content + '
' content = re.sub(r"```(.*?)```", escape_repl, content, flags=re.DOTALL) tree = lxml.html.fromstring(content) cleaner = lxml.html.Cleaner(remove_unknown_tags=False, kill_tags=set(['style']), safe_attrs_only=False) tree = cleaner.clean_html(tree) content = lxml.html.tostring(tree, encoding='utf-8', method='html') # post processing to fix errors content = content[5:-6] # FIXME this is for block quotes, doesn't work for double ">" content = re.sub(r"(\n>)", "\n>", content) content = re.sub(r"(^>)", ">", content) content = re.sub(r"```(.*?)```", unescape_repl, content, flags=re.DOTALL) filename = self.cname_to_filename(to_canonical(name)) f = open(self.path + "/" + filename, 'w') f.write(content) f.close() if create: self.repo.add(filename) if not message: message = "Updated %s" % name if not username: username = self.default_committer_name if not email: email = "%s@realms.io" % username return self.repo.commit(name=username, email=email, message=message, files=[filename]) def rename_page(self, old_name, new_name): old_name, new_name = map(self.cname_to_filename, [old_name, new_name]) self.repo.mv([(old_name, new_name)]) self.repo.commit(name=self.default_committer_name, email=self.default_committer_email, message="Moving %s to %s" % (old_name, new_name), files=[old_name]) def get_page(self, name, sha='HEAD'): # commit = gittle.utils.git.commit_info(self.repo[sha]) name = self.cname_to_filename(name) try: return self.repo.get_commit_files(sha, paths=[name]).get(name) except KeyError: # HEAD doesn't exist yet return None def compare(self, name, old_sha, new_sha): old = self.get_page(name, sha=old_sha) new = self.get_page(name, sha=new_sha) return ghdiff.diff(old['data'], new['data']) def get_history(self, name): return self.repo.file_history(self.cname_to_filename(name)) def cname_to_filename(self, cname): return cname.lower() + ".md"