15
15
# You should have received a copy of the GNU General Public License
16
16
# along with this program; if not, write to the Free Software
17
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
# Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
25
import bzrlib.textfile
28
from paste.httpexceptions import HTTPBadRequest, HTTPServerError
30
from loggerhead.controllers import TemplatedBranchView
32
from loggerhead.highlight import highlight
22
from breezy.errors import BinaryFile, NoSuchId, NoSuchRevision
25
from breezy.transport import NoSuchFile
27
from breezy.errors import NoSuchFile
29
import breezy.textfile
30
from breezy import osutils, urlutils
31
from paste.httpexceptions import (HTTPBadRequest, HTTPMovedPermanently,
34
from ..controllers import TemplatedBranchView
37
from ..highlight import highlight
33
38
except ImportError:
35
from loggerhead import util
38
43
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)
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)
53
file_text = file_text.decode(encoding)
62
file_text.decode(encoding)
54
63
except UnicodeDecodeError:
55
64
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)
65
file_text.decode(encoding)
67
file_lines = osutils.split_lines(file_text)
68
# This can throw breezy.errors.BinaryFile (which our caller catches).
69
breezy.textfile.check_text_lines(file_lines)
71
file_text = file_text.decode(encoding)
72
file_lines = osutils.split_lines(file_text)
62
74
if highlight is not None:
63
75
hl_lines = highlight(file_name, file_text, encoding)
64
76
# highlight strips off extra newlines at the end of the file.
65
77
extra_lines = len(file_lines) - len(hl_lines)
66
78
hl_lines.extend([u''] * extra_lines)
68
hl_lines = map(cgi.escape, file_lines)
72
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):
74
file_lines = self.text_lines(file_id, revid)
75
except bzrlib.errors.BinaryFile:
86
file_lines = self.text_lines(path, revid)
76
88
# bail out; this isn't displayable text
77
89
return ['(This is a binary file.)']
82
94
history = self._history
83
95
branch = history._branch
84
96
revid = self.get_revid()
85
revid = history.fix_revid(revid)
86
file_id = kwargs.get('file_id', None)
87
if (file_id is None) and (path is None):
88
raise HTTPBadRequest('No file_id or filename '
92
file_id = history.get_file_id(revid, path)
94
# no navbar for revisions
95
navigation = util.Container()
98
path = history.get_path(revid, file_id)
98
raise HTTPBadRequest('No filename provided to view')
100
if not history.file_exists(revid, path):
99
103
filename = os.path.basename(path)
101
change = history.get_changes([ revid ])[0]
105
change = history.get_changes([revid])[0]
102
106
# If we're looking at the tip, use head: in the URL instead
103
107
if revid == branch.last_revision():
104
108
revno_url = 'head:'
112
116
self._branch.is_root,
119
tree = history.revision_tree(revid)
115
121
# Create breadcrumb trail for the path within the branch
122
branch_breadcrumbs = util.branch_breadcrumbs(path, tree, 'files')
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')
125
if tree.kind(path) == "directory":
126
raise HTTPMovedPermanently(
127
self._branch.context_url(['/files', revno_url, path]))
131
# no navbar for revisions
132
navigation = util.Container()
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.
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.
128
139
'revno_url': revno_url,
130
140
'file_path': path,
131
141
'filename': filename,
132
142
'navigation': navigation,
133
143
'change': change,
134
'contents': self.file_contents(file_id, revid),
144
'contents': self.file_contents(path, revid),
135
145
'fileview_active': True,
136
146
'directory_breadcrumbs': directory_breadcrumbs,
137
147
'branch_breadcrumbs': branch_breadcrumbs,