23
from paste.httpexceptions import HTTPBadRequest
24
import bzrlib.textfile
27
from paste.httpexceptions import HTTPBadRequest, HTTPServerError, HTTPMovedPermanently
25
29
from loggerhead.controllers import TemplatedBranchView
31
from loggerhead.highlight import highlight
26
34
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])
37
class ViewUI(TemplatedBranchView):
39
template_path = 'loggerhead.templates.view'
41
def tree_for(self, file_id, revid):
42
file_revid = self._history.get_inventory(revid)[file_id].revision
43
return self._history._branch.repository.revision_tree(file_revid)
45
def text_lines(self, file_id, revid):
46
file_name = os.path.basename(self._history.get_path(revid, file_id))
48
tree = self.tree_for(file_id, revid)
49
file_text = tree.get_file_text(file_id)
52
file_text = file_text.decode(encoding)
53
except UnicodeDecodeError:
54
encoding = 'iso-8859-15'
55
file_text = file_text.decode(encoding)
57
file_lines = bzrlib.osutils.split_lines(file_text)
58
# This can throw bzrlib.errors.BinaryFile (which our caller catches).
59
bzrlib.textfile.check_text_lines(file_lines)
61
if highlight is not None:
62
hl_lines = highlight(file_name, file_text, encoding)
63
# highlight strips off extra newlines at the end of the file.
64
extra_lines = len(file_lines) - len(hl_lines)
65
hl_lines.extend([u''] * extra_lines)
47
path = '/'.join(args[1:])
48
if not path.startswith('/'):
51
file_id = kw.get('file_id', None)
67
hl_lines = map(util.html_escape, file_lines)
71
def file_contents(self, file_id, revid):
73
file_lines = self.text_lines(file_id, revid)
74
except bzrlib.errors.BinaryFile:
75
# bail out; this isn't displayable text
76
return ['(This is a binary file.)']
80
def get_values(self, path, kwargs, headers):
81
history = self._history
82
branch = history._branch
83
revid = self.get_revid()
84
revid = history.fix_revid(revid)
85
file_id = kwargs.get('file_id', None)
52
86
if (file_id is None) and (path is None):
53
raise HTTPBadRequest('No file_id or filename provided to annotate')
87
raise HTTPBadRequest('No file_id or filename '
55
90
if file_id is None:
56
file_id = h.get_file_id(revid, path)
91
file_id = history.get_file_id(revid, path)
58
93
# no navbar for revisions
59
94
navigation = util.Container()
62
path = h.get_path(revid, file_id)
97
path = history.get_path(revid, file_id)
63
98
filename = os.path.basename(path)
100
change = history.get_changes([ revid ])[0]
101
# If we're looking at the tip, use head: in the URL instead
102
if revid == branch.last_revision():
105
revno_url = history.get_revno(revid)
107
# Directory Breadcrumbs
108
directory_breadcrumbs = (
109
util.directory_breadcrumbs(
110
self._branch.friendly_name,
111
self._branch.is_root,
114
# Create breadcrumb trail for the path within the branch
116
inv = history.get_inventory(revid)
118
self.log.exception('Exception fetching changes')
119
raise HTTPServerError('Could not fetch changes')
120
branch_breadcrumbs = util.branch_breadcrumbs(path, inv, 'files')
122
if inv[file_id].kind == "directory":
123
raise HTTPMovedPermanently(self._branch.context_url(['/files', revno_url, path]))
126
# In AnnotateUI, "annotated" is a dictionary mapping lines to changes.
127
# We exploit the fact that bool({}) is False when checking whether
128
# we're in "annotated" mode.
130
'revno_url': revno_url,
67
131
'file_id': file_id,
69
133
'filename': filename,
70
134
'navigation': navigation,
71
'change': h.get_changes([ revid ])[0],
72
'contents': list(h.annotate_file(file_id, revid)),
136
'contents': self.file_contents(file_id, revid),
73
137
'fileview_active': True,
138
'directory_breadcrumbs': directory_breadcrumbs,
139
'branch_breadcrumbs': branch_breadcrumbs,