17
17
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23
from paste.httpexceptions import HTTPBadRequest
25
import bzrlib.textfile
28
from paste.httpexceptions import HTTPBadRequest, HTTPServerError
25
30
from loggerhead.controllers import TemplatedBranchView
32
from loggerhead.highlight import highlight
26
35
from loggerhead import util
30
while path.endswith('/'):
32
path = posixpath.dirname(path)
35
class AnnotateUI (TemplatedBranchView):
37
template_path = 'loggerhead.templates.annotate'
39
def get_values(self, h, args, kw, headers):
41
revid = h.fix_revid(args[0])
38
class ViewUI(TemplatedBranchView):
40
template_path = 'loggerhead.templates.view'
42
def tree_for(self, file_id, revid):
43
file_revid = self._history.get_inventory(revid)[file_id].revision
44
return self._history._branch.repository.revision_tree(file_revid)
46
def text_lines(self, file_id, revid):
47
file_name = os.path.basename(self._history.get_path(revid, file_id))
49
tree = self.tree_for(file_id, revid)
50
file_text = tree.get_file_text(file_id)
53
file_text = file_text.decode(encoding)
54
except UnicodeDecodeError:
55
encoding = 'iso-8859-15'
56
file_text = file_text.decode(encoding)
58
file_lines = bzrlib.osutils.split_lines(file_text)
59
# This can throw bzrlib.errors.BinaryFile (which our caller catches).
60
bzrlib.textfile.check_text_lines(file_lines)
62
if highlight is not None:
63
hl_lines = highlight(file_name, file_text, encoding)
64
# highlight strips off extra newlines at the end of the file.
65
extra_lines = len(file_lines) - len(hl_lines)
66
hl_lines.extend([u''] * extra_lines)
47
path = '/'.join(args[1:])
48
if not path.startswith('/'):
51
file_id = kw.get('file_id', None)
68
hl_lines = map(cgi.escape, file_lines)
72
def file_contents(self, file_id, revid):
74
file_lines = self.text_lines(file_id, revid)
75
except bzrlib.errors.BinaryFile:
76
# bail out; this isn't displayable text
77
return ['(This is a binary file.)']
81
def get_values(self, path, kwargs, headers):
82
history = self._history
83
branch = history._branch
84
revid = self.get_revid()
85
revid = history.fix_revid(revid)
86
file_id = kwargs.get('file_id', None)
52
87
if (file_id is None) and (path is None):
53
raise HTTPBadRequest('No file_id or filename provided to annotate')
88
raise HTTPBadRequest('No file_id or filename '
55
91
if file_id is None:
56
file_id = h.get_file_id(revid, path)
92
file_id = history.get_file_id(revid, path)
58
94
# no navbar for revisions
59
95
navigation = util.Container()
62
path = h.get_path(revid, file_id)
98
path = history.get_path(revid, file_id)
63
99
filename = os.path.basename(path)
101
change = history.get_changes([ revid ])[0]
102
# If we're looking at the tip, use head: in the URL instead
103
if revid == branch.last_revision():
106
revno_url = history.get_revno(revid)
108
# Directory Breadcrumbs
109
directory_breadcrumbs = (
110
util.directory_breadcrumbs(
111
self._branch.friendly_name,
112
self._branch.is_root,
115
# Create breadcrumb trail for the path within the branch
117
inv = history.get_inventory(revid)
119
self.log.exception('Exception fetching changes')
120
raise HTTPServerError('Could not fetch changes')
121
branch_breadcrumbs = util.branch_breadcrumbs(path, inv, 'files')
124
# In AnnotateUI, "annotated" is a generator giving revision
125
# numbers per lines, but the template checks if "annotated" is
126
# true or not before using it, so we have to define it here also.
128
'revno_url': revno_url,
67
129
'file_id': file_id,
69
131
'filename': filename,
70
132
'navigation': navigation,
71
'change': h.get_changes([ revid ])[0],
72
'contents': list(h.annotate_file(file_id, revid)),
134
'contents': self.file_contents(file_id, revid),
73
135
'fileview_active': True,
136
'directory_breadcrumbs': directory_breadcrumbs,
137
'branch_breadcrumbs': branch_breadcrumbs,