28
from breezy.transport import NoSuchFile
30
from breezy.errors import NoSuchFile
27
35
import breezy.textfile
30
37
from paste.httpexceptions import (
32
39
HTTPMovedPermanently,
37
from loggerhead.controllers import TemplatedBranchView
43
from ..controllers import TemplatedBranchView
39
from loggerhead.highlight import highlight
45
from ..highlight import highlight
40
46
except ImportError:
42
from loggerhead import util
45
51
class ViewUI(TemplatedBranchView):
47
template_path = 'loggerhead.templates.view'
49
def tree_for(self, file_id, revid):
50
file_revid = self._history.get_inventory(revid)[file_id].revision
51
return self._history._branch.repository.revision_tree(file_revid)
53
def text_lines(self, file_id, revid):
54
file_name = os.path.basename(self._history.get_path(revid, file_id))
56
tree = self.tree_for(file_id, revid)
57
file_text = tree.get_file_text(file_id)
53
template_name = 'view'
55
def tree_for(self, path, revid):
56
if not isinstance(path, str):
58
if not isinstance(revid, bytes):
59
raise TypeError(revid)
60
return self._history._branch.repository.revision_tree(revid)
62
def text_lines(self, path, revid):
63
file_name = os.path.basename(path)
65
tree = self.tree_for(path, revid)
66
file_text = tree.get_file_text(path)
60
file_text = file_text.decode(encoding)
70
file_text.decode(encoding)
61
71
except UnicodeDecodeError:
62
72
encoding = 'iso-8859-15'
63
file_text = file_text.decode(encoding)
73
file_text.decode(encoding)
65
file_lines = breezy.osutils.split_lines(file_text)
75
file_lines = osutils.split_lines(file_text)
66
76
# This can throw breezy.errors.BinaryFile (which our caller catches).
67
77
breezy.textfile.check_text_lines(file_lines)
79
file_text = file_text.decode(encoding)
80
file_lines = osutils.split_lines(file_text)
69
82
if highlight is not None:
70
83
hl_lines = highlight(file_name, file_text, encoding)
71
84
# highlight strips off extra newlines at the end of the file.
72
85
extra_lines = len(file_lines) - len(hl_lines)
73
86
hl_lines.extend([u''] * extra_lines)
75
hl_lines = map(util.html_escape, file_lines)
79
def file_contents(self, file_id, revid):
88
hl_lines = [util.html_escape(line) for line in file_lines]
92
def file_contents(self, path, revid):
81
file_lines = self.text_lines(file_id, revid)
94
file_lines = self.text_lines(path, revid)
83
96
# bail out; this isn't displayable text
84
97
return ['(This is a binary file.)']
89
102
history = self._history
90
103
branch = history._branch
91
104
revid = self.get_revid()
92
revid = history.fix_revid(revid)
93
file_id = kwargs.get('file_id', None)
94
if (file_id is None) and (path is None):
95
raise HTTPBadRequest('No file_id or filename '
106
raise HTTPBadRequest('No filename provided to view')
100
file_id = history.get_file_id(revid, path)
102
path = history.get_path(revid, file_id)
103
except (NoSuchId, NoSuchRevision):
108
if not history.file_exists(revid, path):
104
109
raise HTTPNotFound()
106
111
filename = os.path.basename(path)
119
124
self._branch.is_root,
127
tree = history.revision_tree(revid)
122
129
# Create breadcrumb trail for the path within the branch
124
inv = history.get_inventory(revid)
126
self.log.exception('Exception fetching changes')
127
raise HTTPServerError('Could not fetch changes')
128
branch_breadcrumbs = util.branch_breadcrumbs(path, inv, 'files')
130
branch_breadcrumbs = util.branch_breadcrumbs(path, tree, 'files')
133
if tree.kind(path) == "directory":
134
raise HTTPMovedPermanently(
135
self._branch.context_url(['/files', revno_url, path]))
133
137
raise HTTPNotFound()
135
if file.kind == "directory":
136
raise HTTPMovedPermanently(self._branch.context_url(['/files', revno_url, path]))
138
139
# no navbar for revisions
139
140
navigation = util.Container()
142
# In AnnotateUI, "annotated" is a dictionary mapping lines to changes.
143
# We exploit the fact that bool({}) is False when checking whether
144
# we're in "annotated" mode.
143
# In AnnotateUI, "annotated" is a dictionary mapping lines to
144
# changes. We exploit the fact that bool({}) is False when
145
# checking whether we're in "annotated" mode.
146
147
'revno_url': revno_url,
148
148
'file_path': path,
149
149
'filename': filename,
150
150
'navigation': navigation,
151
151
'change': change,
152
'contents': self.file_contents(file_id, revid),
152
'contents': self.file_contents(path, revid),
153
153
'fileview_active': True,
154
154
'directory_breadcrumbs': directory_breadcrumbs,
155
155
'branch_breadcrumbs': branch_breadcrumbs,