Commit c07213ca authored by Christophe Dumez's avatar Christophe Dumez

- HTML Diff is now working (looks like viewcvs)


git-svn-id: https://svn.erp5.org/repos/public/erp5/trunk@6356 20353a03-c40f-0410-a6d1-a30d3c3de9de
parent 1a88de33
......@@ -34,6 +34,7 @@ from MethodObject import Method
from Globals import InitializeClass
from AccessControl import ClassSecurityInfo
from Products.ERP5Type import Permissions
from zLOG import LOG
try:
import pysvn
......@@ -229,7 +230,11 @@ try:
def diff(self, path):
self._getPreferences()
os.system('mkdir -p /tmp/tmp-svn/')
return self.client.diff('/tmp/tmp-svn',path)
return self.client.diff(tmp_path='/tmp/tmp-svn/', url_or_path=path, recurse=False)
def revert(self, path):
self._getPreferences()
return self.client.revert(path)
def newSubversionClient(container, **kw):
return SubversionClient(**kw).__of__(container)
......
......@@ -34,7 +34,7 @@ from Products.ERP5Type import Permissions
from Products.ERP5Subversion import _dtmldir
from zLOG import LOG, WARNING, INFO
from Products.ERP5Subversion.SubversionClient import newSubversionClient
import os
import os, re
from DateTime import DateTime
from cPickle import dumps, loads
from App.config import getConfiguration
......@@ -74,6 +74,221 @@ class Dir :
return d
## End of Dir Class
class DiffFile:
# Members :
# - path : path of the modified file
# - children : sub codes modified
# - old_revision
# - new_revision
def __init__(this, raw_diff):
this.header = raw_diff.split('@@')[0][:-1]
# Getting file path in header
this.path = this.header.split('====')[0][:-1].strip()
# Getting revisions in header
for line in this.header.split('\n'):
if line.startswith('--- '):
tmp = re.search('\\([\w\s]+\\)$', line)
this.old_revision = tmp.string[tmp.start():tmp.end()][1:-1].strip()
if line.startswith('+++ '):
tmp = re.search('\\([\w\s]+\\)$', line)
this.new_revision = tmp.string[tmp.start():tmp.end()][1:-1].strip()
# Splitting the body from the header
this.body = '\n'.join(raw_diff.strip().split('\n')[4:])
# Now splitting modifications
this.children = []
first = True
tmp = []
for line in this.body.split('\n'):
if line:
if line.startswith('@@') and not first:
this.children.append(CodeBlock('\n'.join(tmp)))
tmp = [line,]
else:
first = False
tmp.append(line)
this.children.append(CodeBlock('\n'.join(tmp)))
def _escape(this, data):
"""
Escape &, <, and > in a string of data.
This is a copy of the xml.sax.saxutils.escape function.
"""
# must do ampersand first
if data:
#data = data.replace("&", "&amp;")
data = data.replace(">", "&gt;")
data = data.replace("<", "&lt;")
return data
def toHTML(this):
# Adding header of the table
html = '''<font color='black'><b>%s</b><br>
<hr><br>
<table style="text-align: left; width: 100%%;" border="0" cellpadding="0" cellspacing="0">
<tbody>
<tr height="18px">
<td style="background-color: grey"><b><center>%s</center></b></td>
<td style="background-color: grey"><b><center>%s</center></b></td>
</tr>'''%(this.path, this.old_revision, this.new_revision)
First = True
for child in this.children:
# Adding line number of the modification
if First:
html += '''<tr height="18px"><td style="background-color: grey">&nbsp;</td><td style="background-color: grey">&nbsp;</td></tr> <tr>
<td style="background-color: rgb(68, 132, 255);"><b>Line %s</b></td>
<td style="background-color: rgb(68, 132, 255);"><b>Line %s</b></td>
</tr>'''%(child.old_line, child.new_line)
First = False
else:
html += '''<tr height="18px"><td style="background-color: white">&nbsp;</td><td style="background-color: white">&nbsp;</td></tr> <tr>
<td style="background-color: rgb(68, 132, 255);"><b>Line %s</b></td>
<td style="background-color: rgb(68, 132, 255);"><b>Line %s</b></td>
</tr>'''%(child.old_line, child.new_line)
# Adding diff of the modification
old_code_list = child.getOldCodeList()
new_code_list = child.getNewCodeList()
i=0
for old_line_tuple in old_code_list:
new_line_tuple = new_code_list[i]
if new_line_tuple[0]:
new_line = new_line_tuple[0]
else:
new_line = ' '
if old_line_tuple[0]:
old_line = old_line_tuple[0]
else:
old_line = ' '
i+=1
html += ''' <tr height="18px">
<td style="background-color: %s">%s</td>
<td style="background-color: %s">%s</td>
</tr>'''%(old_line_tuple[1], this._escape(old_line).replace(' ', '&nbsp;').replace('\t', '&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;'), new_line_tuple[1], this._escape(new_line).replace(' ', '&nbsp;').replace('\t', '&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;'))
html += ''' </tbody>
</table></font><br><br>'''
return html
# A code block contains several SubCodeBlocks
class CodeBlock:
# Members :
# - old_line : line in old code (before modif)
# - new line : line in new code (after modif)
#
# Methods :
# - getOldCodeList() : return code before modif
# - getNewCodeList() : return code after modif
# Note: the code returned is a list of tuples (code line, background color)
def __init__(this, raw_diff):
# Splitting body and header
this.body = '\n'.join(raw_diff.split('\n')[1:])
this.header = raw_diff.split('\n')[0]
# Getting modifications lines
tmp = re.search('^@@ -\d+', this.header)
this.old_line = tmp.string[tmp.start():tmp.end()][4:]
tmp = re.search('\+\d+,', this.header)
this.new_line = tmp.string[tmp.start():tmp.end()][1:-1]
# Splitting modifications in SubCodeBlocks
in_modif = False
this.children = []
tmp=[]
for line in this.body.split('\n'):
if line:
if (line.startswith('+') or line.startswith('-')):
if in_modif:
tmp.append(line)
else:
this.children.append(SubCodeBlock('\n'.join(tmp)))
tmp = [line,]
in_modif = True
else:
if in_modif:
this.children.append(SubCodeBlock('\n'.join(tmp)))
tmp = [line,]
in_modif = False
else:
tmp.append(line)
this.children.append(SubCodeBlock('\n'.join(tmp)))
# Return code before modification
def getOldCodeList(this):
tmp = []
for child in this.children:
tmp.extend(child.getOldCodeList())
return tmp
# Return code after modification
def getNewCodeList(this):
tmp = []
for child in this.children:
tmp.extend(child.getNewCodeList())
return tmp
# a SubCodeBlock contain 0 or 1 modification (not more)
class SubCodeBlock:
def __init__(this, code):
this.body=code
this.modification=this._getModif()
# Choosing background color
if this.modification == 'none':
this.color = 'white'
elif this.modification == 'change':
this.color = 'rgb(253, 228, 6);'#light orange
elif this.modification == 'deletion':
this.color = 'rgb(253, 117, 74);'#light red
else:
this.color = 'rgb(83, 253, 74);'#light green
def _getModif(this):
nb_plus = 0
nb_minus = 0
for line in this.body.split('\n'):
if line.startswith("-"):
nb_minus-=1
elif line.startswith("+"):
nb_plus+=1
if (nb_plus!=0 and nb_minus==0):
return 'addition'
if (nb_plus==0 and nb_minus!=0):
return 'deletion'
if (nb_plus==0 and nb_minus==0):
return 'none'
return 'change'
# Return code before modification
def getOldCodeList(this):
if this.modification=='none':
return [(x, 'white') for x in this.body.split('\n')]
elif this.modification=='change':
return [this._getOldCodeList(x) for x in this.body.split('\n') if this._getOldCodeList(x)[0]]
else: # deletion or addition
return [this._getOldCodeList(x) for x in this.body.split('\n')]
def _getOldCodeList(this, line):
if line.startswith('+'):
return (None, this.color)
if line.startswith('-'):
return (' '+line[1:], this.color)
return (line, this.color)
# Return code after modification
def getNewCodeList(this):
if this.modification=='none':
return [(x, 'white') for x in this.body.split('\n')]
elif this.modification=='change':
return [this._getNewCodeList(x) for x in this.body.split('\n') if this._getNewCodeList(x)[0]]
else: # deletion or addition
return [this._getNewCodeList(x) for x in this.body.split('\n')]
def _getNewCodeList(this, line):
if line.startswith('-'):
return (None, this.color)
if line.startswith('+'):
return (' '+line[1:], this.color)
return (line, this.color)
class SubversionTool(UniqueObject, Folder):
"""The SubversionTool provides a Subversion interface to ERP5.
"""
......@@ -193,6 +408,10 @@ class SubversionTool(UniqueObject, Folder):
trust_item_list, permanent = loads(b64decode(login))
return dict(trust_item_list), permanent
def diffHTML(self, file_path):
raw_diff = self.diff(file_path)
return DiffFile(raw_diff).toHTML()
security.declareProtected(Permissions.ManagePortal, 'acceptSSLServer')
def acceptSSLServer(self, trust_dict, permanent=False):
"""Accept a SSL server.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment