def xmlrpc_getDiff(self, pagename, from_rev, to_rev, n_name=None): """ Gets the binary difference between two page revisions. @param pagename: unicode string qualifying the page name @param fromRev: integer specifying the source revision. May be None to refer to a virtual empty revision which leads to a diff containing the whole page. @param toRev: integer specifying the target revision. May be None to refer to the current revision. If the current revision is the same as fromRev, there will be a special error condition "ALREADY_CURRENT" @param n_name: do a tag check verifying that n_name was the normalised name of the last tag If both fromRev and toRev are None, this function acts similar to getPage, i.e. it will diff("",currentRev). @return: Returns a dict: * status (not a field, implicit, returned as Fault if not SUCCESS): * "SUCCESS" - if the diff could be retrieved successfully * "NOT_EXIST" - item does not exist * "FROMREV_INVALID" - the source revision is invalid * "TOREV_INVALID" - the target revision is invalid * "INTERNAL_ERROR" - there was an internal error * "INVALID_TAG" - the last tag does not match the supplied normalised name * "ALREADY_CURRENT" - this not merely an error condition. It rather means that there is no new revision to diff against which is a good thing while synchronisation. * current: the revision number of the current revision (not the one which was diff'ed against) * diff: Binary object that transports a zlib-compressed binary diff (see bdiff.py, taken from Mercurial) * conflict: if there is a conflict on the page currently """ from MoinMoin.util.bdiff import textdiff, compress from MoinMoin.wikisync import TagStore pagename = self._instr(pagename) if n_name is not None: n_name = self._instr(n_name) # User may read page? if not self.request.user.may.read(pagename): return self.notAllowedFault() def allowed_rev_type(data): if data is None: return True return isinstance(data, int) and data > 0 if not allowed_rev_type(from_rev): return xmlrpclib.Fault("FROMREV_INVALID", "Incorrect type for from_rev.") if not allowed_rev_type(to_rev): return xmlrpclib.Fault("TOREV_INVALID", "Incorrect type for to_rev.") currentpage = Page(self.request, pagename) if not currentpage.exists(): return xmlrpclib.Fault("NOT_EXIST", "Page does not exist.") revisions = currentpage.getRevList() if from_rev is not None and from_rev not in revisions: return xmlrpclib.Fault("FROMREV_INVALID", "Unknown from_rev.") if to_rev is not None and to_rev not in revisions: return xmlrpclib.Fault("TOREV_INVALID", "Unknown to_rev.") # use lambda to defer execution in the next lines if from_rev is None: oldcontents = lambda: "" else: oldpage = Page(self.request, pagename, rev=from_rev) oldcontents = lambda: oldpage.get_raw_body_str() if to_rev is None: newpage = currentpage newcontents = lambda: currentpage.get_raw_body_str() else: newpage = Page(self.request, pagename, rev=to_rev) newcontents = lambda: newpage.get_raw_body_str() if oldcontents() and oldpage.get_real_rev() == newpage.get_real_rev(): return xmlrpclib.Fault("ALREADY_CURRENT", "There are no changes.") if n_name is not None: tags = TagStore(newpage) last_tag = tags.get_last_tag() if last_tag is not None and last_tag.normalised_name != n_name: return xmlrpclib.Fault( "INVALID_TAG", "The used tag is incorrect because the normalised name does not match." ) newcontents = newcontents() conflict = wikiutil.containsConflictMarker(newcontents) diffblob = xmlrpclib.Binary( compress(textdiff(oldcontents(), newcontents))) return { "conflict": conflict, "diff": diffblob, "diffversion": 1, "current": currentpage.get_real_rev() }
def xmlrpc_getDiff(self, pagename, from_rev, to_rev, n_name=None): """ Gets the binary difference between two page revisions. @param pagename: unicode string qualifying the page name @param fromRev: integer specifying the source revision. May be None to refer to a virtual empty revision which leads to a diff containing the whole page. @param toRev: integer specifying the target revision. May be None to refer to the current revision. If the current revision is the same as fromRev, there will be a special error condition "ALREADY_CURRENT" @param n_name: do a tag check verifying that n_name was the normalised name of the last tag If both fromRev and toRev are None, this function acts similar to getPage, i.e. it will diff("",currentRev). @return: Returns a dict: * status (not a field, implicit, returned as Fault if not SUCCESS): * "SUCCESS" - if the diff could be retrieved successfully * "NOT_EXIST" - item does not exist * "FROMREV_INVALID" - the source revision is invalid * "TOREV_INVALID" - the target revision is invalid * "INTERNAL_ERROR" - there was an internal error * "INVALID_TAG" - the last tag does not match the supplied normalised name * "ALREADY_CURRENT" - this not merely an error condition. It rather means that there is no new revision to diff against which is a good thing while synchronisation. * current: the revision number of the current revision (not the one which was diff'ed against) * diff: Binary object that transports a zlib-compressed binary diff (see bdiff.py, taken from Mercurial) * conflict: if there is a conflict on the page currently """ from MoinMoin.util.bdiff import textdiff, compress from MoinMoin.wikisync import TagStore pagename = self._instr(pagename) if n_name is not None: n_name = self._instr(n_name) # User may read page? if not self.request.user.may.read(pagename): return self.notAllowedFault() def allowed_rev_type(data): if data is None: return True return isinstance(data, int) and data > 0 if not allowed_rev_type(from_rev): return xmlrpclib.Fault("FROMREV_INVALID", "Incorrect type for from_rev.") if not allowed_rev_type(to_rev): return xmlrpclib.Fault("TOREV_INVALID", "Incorrect type for to_rev.") currentpage = Page(self.request, pagename) if not currentpage.exists(): return xmlrpclib.Fault("NOT_EXIST", "Page does not exist.") revisions = currentpage.getRevList() if from_rev is not None and from_rev not in revisions: return xmlrpclib.Fault("FROMREV_INVALID", "Unknown from_rev.") if to_rev is not None and to_rev not in revisions: return xmlrpclib.Fault("TOREV_INVALID", "Unknown to_rev.") # use lambda to defer execution in the next lines if from_rev is None: oldcontents = lambda: "" else: oldpage = Page(self.request, pagename, rev=from_rev) oldcontents = lambda: oldpage.get_raw_body_str() if to_rev is None: newpage = currentpage newcontents = lambda: currentpage.get_raw_body_str() else: newpage = Page(self.request, pagename, rev=to_rev) newcontents = lambda: newpage.get_raw_body_str() if oldcontents() and oldpage.get_real_rev() == newpage.get_real_rev(): return xmlrpclib.Fault("ALREADY_CURRENT", "There are no changes.") if n_name is not None: tags = TagStore(newpage) last_tag = tags.get_last_tag() if last_tag is not None and last_tag.normalised_name != n_name: return xmlrpclib.Fault("INVALID_TAG", "The used tag is incorrect because the normalised name does not match.") newcontents = newcontents() conflict = wikiutil.containsConflictMarker(newcontents) diffblob = xmlrpclib.Binary(compress(textdiff(oldcontents(), newcontents))) return {"conflict": conflict, "diff": diffblob, "diffversion": 1, "current": currentpage.get_real_rev()}
return xmlrpclib.Fault( "NOT_EXIST", "The page does not exist and no diff was supplied.") if diff is None: # delete the page try: currentpage.deletePage(comment) except PageEditor.AccessDenied, (msg, ): return xmlrpclib.Fault("NOT_ALLOWED", msg) return currentpage.get_real_rev() # base revision used for the diff basepage = Page(self.request, pagename, rev=(delta_remote_rev or 0)) # generate the new page revision by applying the diff newcontents = patch(basepage.get_raw_body_str(), decompress(str(diff))) #print "Diff against %r" % basepage.get_raw_body_str() # write page try: currentpage.saveText(newcontents.decode("utf-8"), last_remote_rev or 0, comment=comment) except PageEditor.Unchanged: # could happen in case of both wiki's pages being equal pass except PageEditor.EditConflict: return LASTREV_INVALID current_rev = currentpage.get_real_rev() tags = TagStore(currentpage)
if not currentpage.exists() and diff is None: return xmlrpclib.Fault("NOT_EXIST", "The page does not exist and no diff was supplied.") if diff is None: # delete the page try: currentpage.deletePage(comment) except PageEditor.AccessDenied, (msg, ): return xmlrpclib.Fault("NOT_ALLOWED", msg) return currentpage.get_real_rev() # base revision used for the diff basepage = Page(self.request, pagename, rev=(delta_remote_rev or 0)) # generate the new page revision by applying the diff newcontents = patch(basepage.get_raw_body_str(), decompress(str(diff))) #print "Diff against %r" % basepage.get_raw_body_str() # write page try: currentpage.saveText(newcontents.decode("utf-8"), last_remote_rev or 0, comment=comment) except PageEditor.Unchanged: # could happen in case of both wiki's pages being equal pass except PageEditor.EditConflict: return LASTREV_INVALID current_rev = currentpage.get_real_rev() tags = TagStore(currentpage) tags.add(remote_wiki=interwiki_name, remote_rev=local_rev, current_rev=current_rev, direction=BOTH, normalised_name=normalised_name)