[patchew-devel] [PATCH 1/9] ansi2html: stub implementation

  • From: Paolo Bonzini <pbonzini@xxxxxxxxxx>
  • To: patchew-devel@xxxxxxxxxxxxx
  • Date: Mon, 26 Feb 2018 12:27:14 +0100

Define the interface, without actually doing much of a conversion.

Signed-off-by: Paolo Bonzini <pbonzini@xxxxxxxxxx>
---
 patchew/logviewer.py    | 50 +++++++++++++++++++++++++++++++++++++++++++++++--
 tests/test_ansi2html.py | 30 +++++++++++++++++++++++++++++
 2 files changed, 78 insertions(+), 2 deletions(-)
 create mode 100644 tests/test_ansi2html.py

diff --git a/patchew/logviewer.py b/patchew/logviewer.py
index 53bf238..4438fa4 100644
--- a/patchew/logviewer.py
+++ b/patchew/logviewer.py
@@ -1,10 +1,41 @@
+# Convert ANSI sequences to HTML for Patchew
+#
+# Copyright (C) 2018 Red Hat, Inc.
+#
+# Author: Paolo Bonzini <pbonzini@xxxxxxxxxx>
+
 import abc
+import sys
 
 from django.views import View
 from django.http import HttpResponse, StreamingHttpResponse
 from django.utils.html import format_html
 from django.utils.safestring import mark_safe
 
+class ANSI2HTMLConverter(object):
+    def __init__(self, white_bg=False):
+        self.prefix = '<pre class="ansi">'
+
+    def _write_prefix(self):
+        if self.prefix != '':
+            yield self.prefix
+            self.prefix = ''
+
+    def convert(self, input):
+        yield from self._write_prefix()
+        yield format_html('{}', input)
+
+    def finish(self):
+        yield from self._write_prefix()
+        yield '</pre>'
+        self.prefix = '<pre class="ansi">'
+
+def ansi2html(input, white_bg=False):
+    c = ANSI2HTMLConverter(white_bg=white_bg)
+    yield from c.convert(input)
+    yield from c.finish()
+
+
 class LogView(View, metaclass=abc.ABCMeta):
     @abc.abstractmethod
     def content(request, **kwargs):
@@ -16,6 +47,9 @@ class LogView(View, metaclass=abc.ABCMeta):
     # prolog includes Bootstrap's pre formatting (for consistency with
     # the parent window's <pre> tags) and and a script to close the
     # colorbox on Esc.
+    # Putting this in a template would be nice, but it would also
+    # consume more memory because we would not be able to just
+    # "yield from" into the StreamingHttpResponse.
     HTML_PROLOG = mark_safe("""<!DOCTYPE html><html><head>
 <style type="text/css">*{margin:0px;padding:0px;background:#333}
 pre { font-size: 13px; line-height: 1.42857143; white-space: pre-wrap; 
word-wrap: break-word; max-width: 100%; color: #eee}
@@ -31,11 +65,23 @@ if (parent.jQuery && parent.jQuery.colorbox) {
 }</script><body>""")
 
     def generate_html(self):
-        return format_html('{}<pre>{}</pre>', self.HTML_PROLOG, self.text)
+        yield self.HTML_PROLOG
+        yield from ansi2html(self.text)
 
     def get(self, request, **kwargs):
         self.text = self.content(request, **kwargs)
         if request.GET.get('html', None) != '1':
             return HttpResponse(self.text, content_type='text/plain')
 
-        return HttpResponse(self.generate_html())
+        return StreamingHttpResponse(self.generate_html())
+
+if __name__ == "__main__":
+    import io
+    c = ANSI2HTMLConverter()
+    # Never split lines at \r
+    sys.stdin = io.TextIOWrapper(sys.stdin.buffer, newline='\n')
+    for line in sys.stdin:
+        for output in c.convert(line):
+            sys.stdout.write(output)
+    for output in c.finish():
+        sys.stdout.write(output)
diff --git a/tests/test_ansi2html.py b/tests/test_ansi2html.py
new file mode 100644
index 0000000..5ad993b
--- /dev/null
+++ b/tests/test_ansi2html.py
@@ -0,0 +1,30 @@
+# Test conversion of ANSI sequences into HTML
+#
+# Copyright (C) 2018 Red Hat, Inc.
+#
+# Author: Paolo Bonzini <pbonzini@xxxxxxxxxx>
+
+import unittest
+
+from patchew.logviewer import ansi2html
+
+class ANSI2HTMLTest(unittest.TestCase):
+    def assertAnsi(self, test, expected, **kwargs):
+        self.assertEqual(''.join(ansi2html(test, **kwargs)),
+                         '<pre class="ansi">%s</pre>' % expected,
+                         repr(test))
+
+    def assertBlackBg(self, test, expected):
+        self.assertAnsi(test, expected)
+
+    def assertWhiteBg(self, test, expected):
+        self.assertAnsi(test, expected, white_bg=True)
+
+    # basic formatting tests
+    def test_basic(self):
+        self.assertBlackBg('a\nbc', 'a\nbc')
+        self.assertBlackBg('<', '&lt;')
+
+
+if __name__ == '__main__':
+    unittest.main()
-- 
2.14.3



Other related posts:

  • » [patchew-devel] [PATCH 1/9] ansi2html: stub implementation - Paolo Bonzini