##// END OF EJS Templates
vcs: always return bytes from node.content...
Mads Kiilerich -
r7942:9203621c default
parent child Browse files
Show More
@@ -182,7 +182,7 b' class GistsController(BaseController):'
182 log.error(traceback.format_exc())
182 log.error(traceback.format_exc())
183 raise HTTPNotFound()
183 raise HTTPNotFound()
184 if format == 'raw':
184 if format == 'raw':
185 content = '\n\n'.join([f.content for f in c.files if (f_path is None or safe_unicode(f.path) == f_path)])
185 content = '\n\n'.join([safe_unicode(f.content) for f in c.files if (f_path is None or safe_unicode(f.path) == f_path)])
186 response.content_type = 'text/plain'
186 response.content_type = 'text/plain'
187 return content
187 return content
188 return render('admin/gists/show.html')
188 return render('admin/gists/show.html')
@@ -272,7 +272,7 b' class CompareController(BaseRepoControll'
272 ignore_whitespace=ignore_whitespace,
272 ignore_whitespace=ignore_whitespace,
273 context=line_context)
273 context=line_context)
274
274
275 diff_processor = diffs.DiffProcessor(raw_diff or '', diff_limit=diff_limit)
275 diff_processor = diffs.DiffProcessor(raw_diff, diff_limit=diff_limit)
276 c.limited_diff = diff_processor.limited_diff
276 c.limited_diff = diff_processor.limited_diff
277 c.file_diff_data = []
277 c.file_diff_data = []
278 c.lines_added = 0
278 c.lines_added = 0
@@ -94,7 +94,7 b' class FeedController(BaseRepoController)'
94 desc_msg.extend(changes)
94 desc_msg.extend(changes)
95 if str2bool(CONFIG.get('rss_include_diff', False)):
95 if str2bool(CONFIG.get('rss_include_diff', False)):
96 desc_msg.append('\n\n')
96 desc_msg.append('\n\n')
97 desc_msg.append(raw_diff)
97 desc_msg.append(safe_unicode(raw_diff))
98 desc_msg.append('</pre>')
98 desc_msg.append('</pre>')
99 return [safe_unicode(chunk) for chunk in desc_msg]
99 return [safe_unicode(chunk) for chunk in desc_msg]
100
100
@@ -46,7 +46,7 b' from kallithea.lib.auth import HasRepoPe'
46 from kallithea.lib.base import BaseRepoController, jsonify, render
46 from kallithea.lib.base import BaseRepoController, jsonify, render
47 from kallithea.lib.exceptions import NonRelativePathError
47 from kallithea.lib.exceptions import NonRelativePathError
48 from kallithea.lib.utils import action_logger
48 from kallithea.lib.utils import action_logger
49 from kallithea.lib.utils2 import convert_line_endings, detect_mode, safe_int, safe_str, str2bool
49 from kallithea.lib.utils2 import convert_line_endings, detect_mode, safe_int, safe_str, safe_unicode, str2bool
50 from kallithea.lib.vcs.backends.base import EmptyChangeset
50 from kallithea.lib.vcs.backends.base import EmptyChangeset
51 from kallithea.lib.vcs.conf import settings
51 from kallithea.lib.vcs.conf import settings
52 from kallithea.lib.vcs.exceptions import (
52 from kallithea.lib.vcs.exceptions import (
@@ -365,8 +365,7 b' class FilesController(BaseRepoController'
365 c.f_path = f_path
365 c.f_path = f_path
366
366
367 if r_post:
367 if r_post:
368
368 old_content = safe_unicode(c.file.content)
369 old_content = c.file.content
370 sl = old_content.splitlines(1)
369 sl = old_content.splitlines(1)
371 first_line = sl[0] if sl else ''
370 first_line = sl[0] if sl else ''
372 # modes: 0 - Unix, 1 - Mac, 2 - DOS
371 # modes: 0 - Unix, 1 - Mac, 2 - DOS
@@ -591,7 +591,7 b' class PullrequestsController(BaseRepoCon'
591 ignore_whitespace=ignore_whitespace, context=line_context)
591 ignore_whitespace=ignore_whitespace, context=line_context)
592 except ChangesetDoesNotExistError:
592 except ChangesetDoesNotExistError:
593 raw_diff = _("The diff can't be shown - the PR revisions could not be found.")
593 raw_diff = _("The diff can't be shown - the PR revisions could not be found.")
594 diff_processor = diffs.DiffProcessor(raw_diff or '', diff_limit=diff_limit)
594 diff_processor = diffs.DiffProcessor(raw_diff, diff_limit=diff_limit)
595 c.limited_diff = diff_processor.limited_diff
595 c.limited_diff = diff_processor.limited_diff
596 c.file_diff_data = []
596 c.file_diff_data = []
597 c.lines_added = 0
597 c.lines_added = 0
@@ -46,7 +46,7 b' from kallithea.lib.celerylib.tasks impor'
46 from kallithea.lib.compat import json
46 from kallithea.lib.compat import json
47 from kallithea.lib.markup_renderer import MarkupRenderer
47 from kallithea.lib.markup_renderer import MarkupRenderer
48 from kallithea.lib.page import Page
48 from kallithea.lib.page import Page
49 from kallithea.lib.utils2 import safe_int
49 from kallithea.lib.utils2 import safe_int, safe_unicode
50 from kallithea.lib.vcs.backends.base import EmptyChangeset
50 from kallithea.lib.vcs.backends.base import EmptyChangeset
51 from kallithea.lib.vcs.exceptions import ChangesetError, EmptyRepositoryError, NodeDoesNotExistError
51 from kallithea.lib.vcs.exceptions import ChangesetError, EmptyRepositoryError, NodeDoesNotExistError
52 from kallithea.lib.vcs.nodes import FileNode
52 from kallithea.lib.vcs.nodes import FileNode
@@ -84,7 +84,7 b' class SummaryController(BaseRepoControll'
84 readme_file = f
84 readme_file = f
85 log.debug('Found README file `%s` rendering...',
85 log.debug('Found README file `%s` rendering...',
86 readme_file)
86 readme_file)
87 readme_data = renderer.render(readme.content,
87 readme_data = renderer.render(safe_unicode(readme.content),
88 filename=f)
88 filename=f)
89 break
89 break
90 except NodeDoesNotExistError:
90 except NodeDoesNotExistError:
@@ -30,6 +30,7 b' from pygments.formatters import HtmlForm'
30
30
31 from kallithea.lib.vcs.exceptions import VCSError
31 from kallithea.lib.vcs.exceptions import VCSError
32 from kallithea.lib.vcs.nodes import FileNode
32 from kallithea.lib.vcs.nodes import FileNode
33 from kallithea.lib.vcs.utils import safe_unicode
33
34
34
35
35 def annotate_highlight(filenode, annotate_from_changeset_func=None,
36 def annotate_highlight(filenode, annotate_from_changeset_func=None,
@@ -53,7 +54,7 b' def annotate_highlight(filenode, annotat'
53 headers=headers,
54 headers=headers,
54 annotate_from_changeset_func=annotate_from_changeset_func, **options)
55 annotate_from_changeset_func=annotate_from_changeset_func, **options)
55 lexer = get_custom_lexer(filenode.extension) or filenode.lexer
56 lexer = get_custom_lexer(filenode.extension) or filenode.lexer
56 highlighted = highlight(filenode.content, lexer, formatter)
57 highlighted = highlight(safe_unicode(filenode.content), lexer, formatter)
57 return highlighted
58 return highlighted
58
59
59
60
@@ -289,8 +289,8 b' class DiffProcessor(object):'
289 based on that parameter cut off will be triggered, set to None
289 based on that parameter cut off will be triggered, set to None
290 to show full diff
290 to show full diff
291 """
291 """
292 if not isinstance(diff, basestring):
292 if not isinstance(diff, bytes):
293 raise Exception('Diff must be a basestring got %s instead' % type(diff))
293 raise Exception('Diff must be bytes - got %s' % type(diff))
294
294
295 self._diff = diff
295 self._diff = diff
296 self.adds = 0
296 self.adds = 0
@@ -516,6 +516,9 b' def _escaper(string):'
516 """, re.VERBOSE | re.MULTILINE)
516 """, re.VERBOSE | re.MULTILINE)
517
517
518
518
519 _header_next_check = re.compile(br'''(?!@)(?!literal )(?!delta )''')
520
521
519 def _get_header(vcs, diff_chunk):
522 def _get_header(vcs, diff_chunk):
520 """
523 """
521 Parses a Git diff for a single file (header and chunks) and returns a tuple with:
524 Parses a Git diff for a single file (header and chunks) and returns a tuple with:
@@ -537,7 +540,7 b' def _get_header(vcs, diff_chunk):'
537 raise Exception('diff not recognized as valid %s diff' % vcs)
540 raise Exception('diff not recognized as valid %s diff' % vcs)
538 meta_info = match.groupdict()
541 meta_info = match.groupdict()
539 rest = diff_chunk[match.end():]
542 rest = diff_chunk[match.end():]
540 if rest and not rest.startswith('@') and not rest.startswith('literal ') and not rest.startswith('delta '):
543 if rest and _header_next_check.match(rest):
541 raise Exception('cannot parse %s diff header: %r followed by %r' % (vcs, diff_chunk[:match.end()], rest[:1000]))
544 raise Exception('cannot parse %s diff header: %r followed by %r' % (vcs, diff_chunk[:match.end()], rest[:1000]))
542 diff_lines = (_escaper(m.group(0)) for m in re.finditer(r'.*\n|.+$', rest)) # don't split on \r as str.splitlines do
545 diff_lines = (_escaper(m.group(0)) for m in re.finditer(r'.*\n|.+$', rest)) # don't split on \r as str.splitlines do
543 return meta_info, diff_lines
546 return meta_info, diff_lines
@@ -330,7 +330,7 b' def pygmentize(filenode, **kwargs):'
330 """
330 """
331 lexer = get_custom_lexer(filenode.extension) or filenode.lexer
331 lexer = get_custom_lexer(filenode.extension) or filenode.lexer
332 return literal(markup_whitespace(
332 return literal(markup_whitespace(
333 code_highlight(filenode.content, lexer, CodeHtmlFormatter(**kwargs))))
333 code_highlight(safe_unicode(filenode.content), lexer, CodeHtmlFormatter(**kwargs))))
334
334
335
335
336 def pygmentize_annotation(repo_name, filenode, **kwargs):
336 def pygmentize_annotation(repo_name, filenode, **kwargs):
@@ -182,12 +182,13 b' class WhooshIndexingDaemon(object):'
182
182
183 indexed = indexed_w_content = 0
183 indexed = indexed_w_content = 0
184 if self.is_indexable_node(node):
184 if self.is_indexable_node(node):
185 u_content = node.content
185 bytes_content = node.content
186 if not isinstance(u_content, unicode):
186 if b'\0' in bytes_content:
187 log.warning(' >> %s - no text content', path)
187 log.warning(' >> %s - no text content', path)
188 u_content = u''
188 u_content = u''
189 else:
189 else:
190 log.debug(' >> %s', path)
190 log.debug(' >> %s', path)
191 u_content = safe_unicode(bytes_content)
191 indexed_w_content += 1
192 indexed_w_content += 1
192
193
193 else:
194 else:
@@ -68,11 +68,7 b' class GitInMemoryChangeset(BaseInMemoryC'
68 # for dirnames (in reverse order) [this only applies for nodes from added]
68 # for dirnames (in reverse order) [this only applies for nodes from added]
69 new_trees = []
69 new_trees = []
70
70
71 if not node.is_binary:
71 blob = objects.Blob.from_string(node.content)
72 content = node.content.encode(ENCODING)
73 else:
74 content = node.content
75 blob = objects.Blob.from_string(content)
76
72
77 node_path = safe_bytes(node.name)
73 node_path = safe_bytes(node.name)
78 if dirnames:
74 if dirnames:
@@ -52,8 +52,7 b' class MercurialInMemoryChangeset(BaseInM'
52 for node in self.added:
52 for node in self.added:
53 if node.path == path:
53 if node.path == path:
54 return memfilectx(_repo, memctx, path=node.path,
54 return memfilectx(_repo, memctx, path=node.path,
55 data=(node.content.encode('utf-8')
55 data=node.content,
56 if not node.is_binary else node.content),
57 islink=False,
56 islink=False,
58 isexec=node.is_executable,
57 isexec=node.is_executable,
59 copysource=False)
58 copysource=False)
@@ -62,8 +61,7 b' class MercurialInMemoryChangeset(BaseInM'
62 for node in self.changed:
61 for node in self.changed:
63 if node.path == path:
62 if node.path == path:
64 return memfilectx(_repo, memctx, path=node.path,
63 return memfilectx(_repo, memctx, path=node.path,
65 data=(node.content.encode('utf-8')
64 data=node.content,
66 if not node.is_binary else node.content),
67 islink=False,
65 islink=False,
68 isexec=node.is_executable,
66 isexec=node.is_executable,
69 copysource=False)
67 copysource=False)
@@ -16,7 +16,7 b' import stat'
16
16
17 from kallithea.lib.vcs.backends.base import EmptyChangeset
17 from kallithea.lib.vcs.backends.base import EmptyChangeset
18 from kallithea.lib.vcs.exceptions import NodeError, RemovedFileNodeError
18 from kallithea.lib.vcs.exceptions import NodeError, RemovedFileNodeError
19 from kallithea.lib.vcs.utils import safe_str, safe_unicode
19 from kallithea.lib.vcs.utils import safe_bytes, safe_str, safe_unicode
20 from kallithea.lib.vcs.utils.lazy import LazyProperty
20 from kallithea.lib.vcs.utils.lazy import LazyProperty
21
21
22
22
@@ -263,6 +263,10 b' class FileNode(Node):'
263 raise NodeError("Cannot use both content and changeset")
263 raise NodeError("Cannot use both content and changeset")
264 super(FileNode, self).__init__(path, kind=NodeKind.FILE)
264 super(FileNode, self).__init__(path, kind=NodeKind.FILE)
265 self.changeset = changeset
265 self.changeset = changeset
266 if not isinstance(content, bytes) and content is not None:
267 # File content is one thing that inherently must be bytes ... but
268 # VCS module tries to be "user friendly" and support unicode ...
269 content = safe_bytes(content)
266 self._content = content
270 self._content = content
267 self._mode = mode or 0o100644
271 self._mode = mode or 0o100644
268
272
@@ -278,25 +282,17 b' class FileNode(Node):'
278 mode = self._mode
282 mode = self._mode
279 return mode
283 return mode
280
284
281 def _get_content(self):
285 @property
286 def content(self):
287 """
288 Returns lazily byte content of the FileNode.
289 """
282 if self.changeset:
290 if self.changeset:
283 content = self.changeset.get_file_content(self.path)
291 content = self.changeset.get_file_content(self.path)
284 else:
292 else:
285 content = self._content
293 content = self._content
286 return content
294 return content
287
295
288 @property
289 def content(self):
290 """
291 Returns lazily content of the FileNode. If possible, would try to
292 decode content from UTF-8.
293 """
294 content = self._get_content()
295
296 if bool(content and '\0' in content):
297 return content
298 return safe_unicode(content)
299
300 @LazyProperty
296 @LazyProperty
301 def size(self):
297 def size(self):
302 if self.changeset:
298 if self.changeset:
@@ -366,7 +362,7 b' class FileNode(Node):'
366 """
362 """
367 from pygments import lexers
363 from pygments import lexers
368 try:
364 try:
369 lexer = lexers.guess_lexer_for_filename(self.name, self.content, stripnl=False)
365 lexer = lexers.guess_lexer_for_filename(self.name, safe_unicode(self.content), stripnl=False)
370 except lexers.ClassNotFound:
366 except lexers.ClassNotFound:
371 lexer = lexers.TextLexer(stripnl=False)
367 lexer = lexers.TextLexer(stripnl=False)
372 # returns first alias
368 # returns first alias
@@ -414,8 +410,7 b' class FileNode(Node):'
414 """
410 """
415 Returns True if file has binary content.
411 Returns True if file has binary content.
416 """
412 """
417 _bin = '\0' in self._get_content()
413 return b'\0' in self.content
418 return _bin
419
414
420 def is_browser_compatible_image(self):
415 def is_browser_compatible_image(self):
421 return self.mimetype in [
416 return self.mimetype in [
@@ -3,6 +3,7 b' from pygments.formatters import HtmlForm'
3
3
4 from kallithea.lib.vcs.exceptions import VCSError
4 from kallithea.lib.vcs.exceptions import VCSError
5 from kallithea.lib.vcs.nodes import FileNode
5 from kallithea.lib.vcs.nodes import FileNode
6 from kallithea.lib.vcs.utils import safe_unicode
6
7
7
8
8 def annotate_highlight(filenode, annotate_from_changeset_func=None,
9 def annotate_highlight(filenode, annotate_from_changeset_func=None,
@@ -24,9 +25,7 b' def annotate_highlight(filenode, annotat'
24 formatter = AnnotateHtmlFormatter(filenode=filenode, order=order,
25 formatter = AnnotateHtmlFormatter(filenode=filenode, order=order,
25 headers=headers,
26 headers=headers,
26 annotate_from_changeset_func=annotate_from_changeset_func, **options)
27 annotate_from_changeset_func=annotate_from_changeset_func, **options)
27 lexer = filenode.lexer
28 return highlight(safe_unicode(filenode.content), filenode.lexer, formatter)
28 highlighted = highlight(filenode.content, lexer, formatter)
29 return highlighted
30
29
31
30
32 class AnnotateHtmlFormatter(HtmlFormatter):
31 class AnnotateHtmlFormatter(HtmlFormatter):
@@ -73,7 +73,7 b''
73 </div>
73 </div>
74 <div class="panel-body no-padding">
74 <div class="panel-body no-padding">
75 <div id="editor_container">
75 <div id="editor_container">
76 <textarea id="editor_${h.FID('f',file.path)}" name="contents" style="display:none">${file.content}</textarea>
76 <textarea id="editor_${h.FID('f',file.path)}" name="contents" style="display:none">${safe_unicode(file.content)}</textarea>
77 </div>
77 </div>
78 </div>
78 </div>
79 </div>
79 </div>
@@ -59,7 +59,7 b''
59 </span>
59 </span>
60 </div>
60 </div>
61 <div class="panel-body no-padding">
61 <div class="panel-body no-padding">
62 <textarea id="editor" name="content" style="display:none">${h.escape(c.file.content)|n}</textarea>
62 <textarea id="editor" name="content" style="display:none">${h.escape(safe_unicode(c.file.content))|n}</textarea>
63 </div>
63 </div>
64 </div>
64 </div>
65 <div>
65 <div>
@@ -596,11 +596,11 b' class TestGitChangeset(object):'
596 for cs in self.repo:
596 for cs in self.repo:
597 assert isinstance(cs.author, unicode)
597 assert isinstance(cs.author, unicode)
598
598
599 def test_repo_files_content_is_unicode(self):
599 def test_repo_files_content_is_bytes(self):
600 changeset = self.repo.get_changeset()
600 changeset = self.repo.get_changeset()
601 for node in changeset.get_node('/'):
601 for node in changeset.get_node('/'):
602 if node.is_file():
602 if node.is_file():
603 assert isinstance(node.content, unicode)
603 assert isinstance(node.content, bytes)
604
604
605 def test_wrong_path(self):
605 def test_wrong_path(self):
606 # There is 'setup.py' in the root dir but not there:
606 # There is 'setup.py' in the root dir but not there:
@@ -544,11 +544,11 b' class TestMercurialChangeset(object):'
544 for cm in self.repo:
544 for cm in self.repo:
545 assert isinstance(cm.author, unicode)
545 assert isinstance(cm.author, unicode)
546
546
547 def test_repo_files_content_is_unicode(self):
547 def test_repo_files_content_is_bytes(self):
548 test_changeset = self.repo.get_changeset(100)
548 test_changeset = self.repo.get_changeset(100)
549 for node in test_changeset.get_node('/'):
549 for node in test_changeset.get_node('/'):
550 if node.is_file():
550 if node.is_file():
551 assert isinstance(node.content, unicode)
551 assert isinstance(node.content, bytes)
552
552
553 def test_wrong_path(self):
553 def test_wrong_path(self):
554 # There is 'setup.py' in the root dir but not there:
554 # There is 'setup.py' in the root dir but not there:
General Comments 0
You need to be logged in to leave comments. Login now