22
from breezy.errors import (
22
from breezy.errors import BinaryFile, NoSuchId, NoSuchRevision
25
from breezy.transport import NoSuchFile
27
from breezy.errors import NoSuchFile
27
29
import breezy.textfile
30
from paste.httpexceptions import (
37
from loggerhead.controllers import TemplatedBranchView
30
from breezy import osutils, urlutils
31
from paste.httpexceptions import (HTTPBadRequest, HTTPMovedPermanently,
34
from ..controllers import TemplatedBranchView
39
from loggerhead.highlight import highlight
37
from ..highlight import highlight
40
38
except ImportError:
42
from loggerhead import util
45
43
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)
45
template_name = 'view'
47
def tree_for(self, path, revid):
48
if not isinstance(path, str):
50
if not isinstance(revid, bytes):
51
raise TypeError(revid)
52
return self._history._branch.repository.revision_tree(revid)
54
def text_lines(self, path, revid):
55
file_name = os.path.basename(path)
57
tree = self.tree_for(path, revid)
58
file_text = tree.get_file_text(path)
60
file_text = file_text.decode(encoding)
62
file_text.decode(encoding)
61
63
except UnicodeDecodeError:
62
64
encoding = 'iso-8859-15'
63
file_text = file_text.decode(encoding)
65
file_text.decode(encoding)
65
file_lines = breezy.osutils.split_lines(file_text)
67
file_lines = osutils.split_lines(file_text)
66
68
# This can throw breezy.errors.BinaryFile (which our caller catches).
67
69
breezy.textfile.check_text_lines(file_lines)
71
file_text = file_text.decode(encoding)
72
file_lines = osutils.split_lines(file_text)
69
74
if highlight is not None:
70
75
hl_lines = highlight(file_name, file_text, encoding)
71
76
# highlight strips off extra newlines at the end of the file.
72
77
extra_lines = len(file_lines) - len(hl_lines)
73
78
hl_lines.extend([u''] * extra_lines)
75
hl_lines = map(util.html_escape, file_lines)
79
def file_contents(self, file_id, revid):
80
hl_lines = [util.html_escape(line) for line in file_lines]
84
def file_contents(self, path, revid):
81
file_lines = self.text_lines(file_id, revid)
86
file_lines = self.text_lines(path, revid)
83
88
# bail out; this isn't displayable text
84
89
return ['(This is a binary file.)']
89
94
history = self._history
90
95
branch = history._branch
91
96
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 '
98
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):
100
if not history.file_exists(revid, path):
104
101
raise HTTPNotFound()
106
103
filename = os.path.basename(path)
119
116
self._branch.is_root,
119
tree = history.revision_tree(revid)
122
121
# 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')
122
branch_breadcrumbs = util.branch_breadcrumbs(path, tree, 'files')
125
if tree.kind(path) == "directory":
126
raise HTTPMovedPermanently(
127
self._branch.context_url(['/files', revno_url, path]))
133
129
raise HTTPNotFound()
135
if file.kind == "directory":
136
raise HTTPMovedPermanently(self._branch.context_url(['/files', revno_url, path]))
138
131
# no navbar for revisions
139
132
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.
135
# In AnnotateUI, "annotated" is a dictionary mapping lines to
136
# changes. We exploit the fact that bool({}) is False when
137
# checking whether we're in "annotated" mode.
146
139
'revno_url': revno_url,
148
140
'file_path': path,
149
141
'filename': filename,
150
142
'navigation': navigation,
151
143
'change': change,
152
'contents': self.file_contents(file_id, revid),
144
'contents': self.file_contents(path, revid),
153
145
'fileview_active': True,
154
146
'directory_breadcrumbs': directory_breadcrumbs,
155
147
'branch_breadcrumbs': branch_breadcrumbs,