X-Git-Url: https://git.mdrn.pl/redakcja.git/blobdiff_plain/5780495e13ec2d55bc2dee96dec372a9ea395462..e33227021472d98ab797912e73427a9a71c5a531:/lib/vstorage/__init__.py diff --git a/lib/vstorage/__init__.py b/lib/vstorage/__init__.py index aeb7338a..5674c1ba 100644 --- a/lib/vstorage/__init__.py +++ b/lib/vstorage/__init__.py @@ -18,9 +18,12 @@ os.environ['HGENCODING'] = 'utf-8' os.environ['HGMERGE'] = "internal:merge" import mercurial.hg -import mercurial.ui import mercurial.revlog import mercurial.util +from mercurial.match import exact as hg_exact_match +from mercurial.cmdutil import walkchangerevs + +from vstorage.hgui import SilentUI def urlquote(url, safe='/'): @@ -129,10 +132,7 @@ class VersionedStorage(object): os.makedirs(self.path) self.repo_path = find_repo_path(self.path) - self.ui = mercurial.ui.ui() - self.ui.quiet = True - self.ui._report_untrusted = False - self.ui.setconfig('ui', 'interactive', False) + self.ui = SilentUI() if self.repo_path is None: self.repo_path = self.path @@ -148,8 +148,8 @@ class VersionedStorage(object): """Close and reopen the repo, to make sure we are up to date.""" self.repo = mercurial.hg.repository(self.ui, self.repo_path) - def _file_path(self, title): - return os.path.join(self.path, urlquote(title, safe='')) + def _file_path(self, title, type='.xml'): + return os.path.join(self.path, urlquote(title, safe='')) + type def _title_to_file(self, title, type=".xml"): return os.path.join(self.repo_prefix, urlquote(title, safe='')) + type @@ -160,7 +160,7 @@ class VersionedStorage(object): return urlunquote(name) def __contains__(self, title): - return urlquote(title) in self.repo['tip'] + return self._title_to_file(title) in self.repo['tip'] def __iter__(self): return self.all_pages() @@ -211,7 +211,7 @@ class VersionedStorage(object): try: filectx_tip = changectx[repo_file] - current_page_rev = filectx_tip.filerev() + current_page_rev = filectx_tip.rev() except mercurial.revlog.LookupError: self.repo.add([repo_file]) current_page_rev = -1 @@ -221,6 +221,8 @@ class VersionedStorage(object): author = '' comment = msg.encode('utf-8') + logger.debug("Commiting %r", repo_file) + self._commit([repo_file], comment, author) def save_data(self, title, data, **kwargs): @@ -273,7 +275,7 @@ class VersionedStorage(object): if ctx is None: raise DocumentNotFound(title) - return ctx.data().decode(self.charset, 'replace'), ctx.filerev() + return ctx.data().decode(self.charset, 'replace'), ctx.rev() def page_text_by_tag(self, title, tag): """Read unicode text of a taged page.""" @@ -282,7 +284,7 @@ class VersionedStorage(object): try: ctx = self.repo[tag][fname] - return ctx.data().decode(self.charset, 'replace'), ctx.filerev() + return ctx.data().decode(self.charset, 'replace'), ctx.rev() except IndexError: raise DocumentNotFound(fname) @@ -305,7 +307,7 @@ class VersionedStorage(object): raise DocumentNotFound(title) return { - "revision": fctx.filerev(), + "revision": fctx.rev(), "date": datetime.datetime.fromtimestamp(fctx.date()[0]), "author": fctx.user().decode("utf-8", 'replace'), "comment": fctx.description().decode("utf-8", 'replace'), @@ -324,52 +326,49 @@ class VersionedStorage(object): """ return guess_mime(self._file_path(title)) - def _find_filectx(self, title, rev=None): + def _find_filectx(self, title, rev=None, oldest=0, newest= -1): """Find the last revision in which the file existed.""" - repo_file = self._title_to_file(title) - changectx = self._changectx() # start with tip - visited = set() - - stack = [changectx] - visited.add(changectx) - - while repo_file not in changectx: - if not stack: - raise DocumentNotFound(title) - - changectx = stack.pop() - for parent in changectx.parents(): - if parent not in visited: - stack.append(parent) - visited.add(parent) - - try: - fctx = changectx[repo_file] - - if rev is not None: - fctx = fctx.filectx(rev) - fctx.filerev() - - return fctx - except (IndexError, LookupError) as e: - raise DocumentNotFound(title) - - def page_history(self, title): + if rev is not None: + oldest, newest = rev, -1 + opts = {"follow": True, "rev": ["%s:%s" % (newest, oldest)]} + def prepare(ctx, fns): + pass + xml_file = self._title_to_file(title) + matchfn = hg_exact_match(self.repo.root, self.repo.getcwd(), [xml_file]) + generator = walkchangerevs(self.repo, matchfn, opts, prepare) + + last = None + current_name = xml_file + for change in generator: + fctx = change[current_name] + renamed = fctx.renamed() + if renamed: + current_name = renamed[0] + last = change + + if last is not None: + return last[current_name] + + # not found + raise DocumentNotFound(title) + + def page_history(self, title, oldest=0, newest= -1): """Iterate over the page's history.""" + opts = {"follow": True, "rev": ["%s:%s" % (newest, oldest)]} + prepare = lambda * args: True + repo_file = self._title_to_file(title) + matchfn = hg_exact_match(self.repo.root, self.repo.getcwd(), [repo_file]) + generator = walkchangerevs(self.repo, matchfn, opts, prepare) - filectx_tip = self._find_filectx(title) - - maxrev = filectx_tip.filerev() - minrev = 0 - for rev in range(maxrev, minrev - 1, -1): - filectx = filectx_tip.filectx(rev) - date = datetime.datetime.fromtimestamp(filectx.date()[0]) - author = filectx.user().decode('utf-8', 'replace') - comment = filectx.description().decode("utf-8", 'replace') - tags = [t.rsplit('#', 1)[-1] for t in filectx.changectx().tags() if '#' in t] + for changeset in generator: + changeset + date = datetime.datetime.fromtimestamp(changeset.date()[0]) + author = changeset.user().decode('utf-8', 'replace') + comment = changeset.description().decode("utf-8", 'replace') + tags = [t.rsplit('#', 1)[-1] for t in changeset.tags() if '#' in t] yield { - "version": rev, + "version": changeset.rev(), "date": date, "author": author, "description": comment, @@ -391,25 +390,21 @@ class VersionedStorage(object): user=user, message=message, date=None, ) - def history(self): + def history(self, newest=None): """Iterate over the history of entire wiki.""" + opts = {"follow": False, "rev": newest} # follow doesn't make sense + prepare = lambda * args: True + repo_file = self._title_to_file(title) + matchfn = hg_exact_match(self.repo.root, self.repo.getcwd(), [repo_file]) + generator = walkchangerevs(self.repo, matchfn, opts, prepare) - changectx = self._changectx() - maxrev = changectx.rev() - minrev = 0 - for wiki_rev in range(maxrev, minrev - 1, -1): - change = self.repo.changectx(wiki_rev) + for change in generator: date = datetime.datetime.fromtimestamp(change.date()[0]) author = change.user().decode('utf-8', 'replace') comment = change.description().decode("utf-8", 'replace') for repo_file in change.files(): - if repo_file.startswith(self.repo_prefix): - title = self._file_to_title(repo_file) - try: - rev = change[repo_file].filerev() - except mercurial.revlog.LookupError: - rev = -1 - yield title, rev, date, author, comment + title = self._file_to_title(repo_file) + yield title, change.rev(), date, author, comment def all_pages(self, type=''): tip = self.repo['tip'] @@ -418,18 +413,11 @@ class VersionedStorage(object): if not filename.startswith('.') and filename.endswith(type) ] - def changed_since(self, rev): - """Return all pages that changed since specified repository revision.""" + def revert(self, pageid, rev, **commit_args): + """ Make the given version of page the current version (reverting changes). """ - try: - last = self.repo.lookup(int(rev)) - except IndexError: - for page in self.all_pages(): - yield page - return - current = self.repo.lookup('tip') - status = self.repo.status(current, last) - modified, added, removed, deleted, unknown, ignored, clean = status - for filename in modified + added + removed + deleted: - if filename.startswith(self.repo_prefix): - yield self._file_to_title(filename) + # Find the old version + fctx = self._find_filectx(pageid, rev) + + # Restore the contents + self.save_data(pageid, fctx.data(), **commit_args)