turn it into a webserver thing
authorJann Horn <jann@thejh.net>
Sun, 1 Sep 2024 23:37:17 +0000 (01:37 +0200)
committerJann Horn <jann@thejh.net>
Sun, 1 Sep 2024 23:37:17 +0000 (01:37 +0200)
app.yaml [new file with mode: 0644]
main.py [moved from threadview.py with 71% similarity]

diff --git a/app.yaml b/app.yaml
new file mode 100644 (file)
index 0000000..98e5a42
--- /dev/null
+++ b/app.yaml
@@ -0,0 +1,7 @@
+runtime: python312
+instance_class: F1
+automatic_scaling:
+  max_instances: 1
+handlers:
+- url: /.*
+  script: auto
similarity index 71%
rename from threadview.py
rename to main.py
index 0de3861..38c0bfd 100755 (executable)
+++ b/main.py
@@ -5,6 +5,7 @@ import email
 import email.policy
 import html
 import mailbox
+from urllib.parse import parse_qs
 
 # for diff preparation:
 # normalize whitespace sequences to single space, for when people reply from
@@ -98,12 +99,12 @@ class TextBlockRange:
         if last_line.lstrip().startswith('On ') and last_line.rstrip().endswith(':'):
             # Check if next block is quote
             check_pos = self.start_pos_orig + self.length_orig
-            print('########   LOOKS LIKE QUOTE: <<'+last_line+'>>')
+            #print('########   LOOKS LIKE QUOTE: <<'+last_line+'>>')
             while check_pos < len(self.message.lines.lines):
                 if self.message.lines.lines[check_pos].real_quote:
                     # is real quote, strip last line
                     self.length_orig -= 1
-                    print('  IS QUOTE!')
+                    #print('  IS QUOTE!')
                     break
                 if not self.message.lines.lines[check_pos].empty:
                     break
@@ -122,17 +123,17 @@ class TextBlockRangeset:
             self.ranges.append(r)
 
     def import_rangeset(self, other_ranges):
-        print('import_rangeset()')
-        print('  own ranges:')
-        for r in self.ranges:
-            print('    '+str(r.start_pos_child)+'-'+str(r.end_pos_child())+'  '+('quote' if r.is_quote else 'new'))
-        print('  import ranges:')
-        for r in other_ranges:
-            print('    '+str(r.pos_parent))
+        #print('import_rangeset()')
+        #print('  own ranges:')
+        #for r in self.ranges:
+        #    print('    '+str(r.start_pos_child)+'-'+str(r.end_pos_child())+'  '+('quote' if r.is_quote else 'new'))
+        #print('  import ranges:')
+        #for r in other_ranges:
+        #    print('    '+str(r.pos_parent))
 
         own_i = 0
         for other_range in other_ranges:
-            print('importing element with pos_parent='+str(other_range.pos_parent))
+            #print('importing element with pos_parent='+str(other_range.pos_parent))
             while own_i != len(self.ranges) and other_range.pos_parent >= self.ranges[own_i].end_pos_child():
                 own_i += 1
             if other_range.pos_parent == -1:
@@ -153,9 +154,9 @@ class TextBlockRangeset:
             other_range.move_up_after(self.ranges[own_i-1])
             self.ranges.insert(own_i, other_range)
 
-        print('  own ranges after:')
-        for r in self.ranges:
-            print('    '+str(r.start_pos_child)+'-'+str(r.end_pos_child())+'  '+('quote' if r.is_quote else 'new')+'  '+r.meta_origin_str())
+        #print('  own ranges after:')
+        #for r in self.ranges:
+        #    print('    '+str(r.start_pos_child)+'-'+str(r.end_pos_child())+'  '+('quote' if r.is_quote else 'new')+'  '+r.meta_origin_str())
 
     def drop_quotes(self):
         self.ranges = list(filter(lambda r: not r.is_quote, self.ranges))
@@ -260,7 +261,7 @@ class ThreadMessage:
             child.dump_tree(level+1, topic_only)
 
     def init_diff_recursively(self):
-        print('init_diff_recursively')
+        #print('init_diff_recursively')
         if self.is_diff_root():
             self.blocks = TextBlockRangeset()
             self.blocks.append(TextBlockRange(self, 0, len(self.lines.lines), -1, False))
@@ -279,7 +280,7 @@ class ThreadMessage:
                 for block in child.blocks.ranges:
                     all_child_blocks.append(block)
         all_child_blocks.sort(key=lambda block:block.pos_parent)
-        print('importing for '+self.id+' from '+self.from_hdr)
+        #print('importing for '+self.id+' from '+self.from_hdr)
         self.blocks.import_rangeset(all_child_blocks)
         self.blocks.drop_quotes()
 
@@ -287,43 +288,46 @@ class ThreadMessage:
             # only do this for diff roots, at the end
             self.blocks.trim_blocks()
 
-mbox = mailbox.mbox('t.mbox', factory=lambda x: email.message_from_binary_file(x, policy=email.policy.default))
-root_message = None
-messages_by_id = {}
-all_messages = []
-all_topic_roots = []
-message_index = 0
-for msg in mbox:
-    tmsg = ThreadMessage(msg, message_index)
-    message_index += 1
-    messages_by_id[tmsg.id] = tmsg
-    #print('have message "'+tmsg.id+'"')
-    all_messages.append(tmsg)
-    if tmsg.parent_id == None:
-        if root_message != None:
-            raise Exception('more than one root message')
-        root_message = tmsg
-    if tmsg.parent_id == None or tmsg.is_patch:
-        all_topic_roots.append(tmsg)
-
-if root_message == None:
-    raise Exception('no root message')
-
-for tmsg in all_messages:
-    #print('looking up message "'+tmsg.parent_id+'"')
-    if not tmsg.parent_id:
-        continue
-    if not tmsg.parent_id in messages_by_id:
-        raise Exception('missing intermediate message')
-    parent_tmsg = messages_by_id[tmsg.parent_id]
-    tmsg.parent = parent_tmsg
-    parent_tmsg.children.append(tmsg)
+def parse_mbox():
+    mbox = mailbox.mbox('t.mbox', factory=lambda x: email.message_from_binary_file(x, policy=email.policy.default))
+    root_message = None
+    messages_by_id = {}
+    all_messages = []
+    all_topic_roots = []
+    message_index = 0
+    for msg in mbox:
+        tmsg = ThreadMessage(msg, message_index)
+        message_index += 1
+        messages_by_id[tmsg.id] = tmsg
+        #print('have message "'+tmsg.id+'"')
+        all_messages.append(tmsg)
+        if tmsg.parent_id == None:
+            if root_message != None:
+                raise Exception('more than one root message')
+            root_message = tmsg
+        if tmsg.parent_id == None or tmsg.is_patch:
+            all_topic_roots.append(tmsg)
+
+    if root_message == None:
+        raise Exception('no root message')
+
+    for tmsg in all_messages:
+        #print('looking up message "'+tmsg.parent_id+'"')
+        if not tmsg.parent_id:
+            continue
+        if not tmsg.parent_id in messages_by_id:
+            raise Exception('missing intermediate message')
+        parent_tmsg = messages_by_id[tmsg.parent_id]
+        tmsg.parent = parent_tmsg
+        parent_tmsg.children.append(tmsg)
+
+    root_message.init_diff_recursively()
+    return all_topic_roots
 
 # note: theoretically we can have loops in the "tree" at this point, but they'd
 # have to be unreachable from the root, so, meh, whatever
 
 #root_message.dump_tree(0, False)
-root_message.init_diff_recursively()
 #messages_by_id['<20240827143852.163123189@linuxfoundation.org>'].init_diff_recursively()
 #for topic in all_topic_roots:
 #    print('TOPIC: '+topic.msg.get('subject', ''))
@@ -331,56 +335,69 @@ root_message.init_diff_recursively()
 #    print('')
 
 
-print('<<<<<<')
+#print('<<<<<<')
 #print(messages_by_id['<20240827143852.163123189@linuxfoundation.org>'].blocks.get_formatted())
-print(root_message.blocks.get_formatted())
-print('>>>>>>')
+#print(root_message.blocks.get_formatted())
+#print('>>>>>>')
 #messages_by_id['<20240827143852.163123189@linuxfoundation.org>'].blocks.dump_meta()
-root_message.blocks.dump_meta()
-
-
-with open('/tmp/lkml-out.html', 'wt') as outfile:
-    outfile.write('<!DOCTYPE html>\n')
-    outfile.write('<html>\n')
-    outfile.write('  <head>\n')
-    outfile.write('    <title>Mehlbrei</title>\n')
-    outfile.write('    <style>\n')
-    outfile.write('      html {height: 100%;width:100%;margin:0px;}\n')
-    outfile.write('      body {display: flex;height: 100%;width:100%;margin:0px;}\n')
-    outfile.write('      #topic_panel {height: 100%; overflow:scroll;flex-shrink:0;}\n')
-    outfile.write('      #main_panel {height: 100%; overflow:scroll;flex-grow:2;}\n')
-    outfile.write('      .topic_link {display:block;}\n')
-    outfile.write('      .empty-topic {opacity: 0.5;}\n')
-    outfile.write('      .alt-content {display:none;}\n')
-    outfile.write('      :target.alt-content {display:block;}\n')
-    outfile.write('      .message-block-container {border: 1px solid black;}\n')
-    outfile.write('      .message-block-meta {font-style: italic; font-weight: bolder;}\n')
-    outfile.write('      .message-block-content {white-space: pre;}\n')
-    outfile.write('    </style>\n')
-    outfile.write('  </head>\n')
-    outfile.write('  <body>\n')
-    outfile.write('    <div id="topic_panel">\n')
-    outfile.write('      <h1>Topics</h1>\n')
+#root_message.blocks.dump_meta()
+
+def app(environ, start_response):
+    out = []
+    query = parse_qs(environ.get('QUERY_STRING', ''))
+    msgid = query.get('msgid', None)
+
+    all_topic_roots = parse_mbox()
+
+    out.append('<!DOCTYPE html>')
+    out.append('<html>')
+    out.append('  <head>')
+    out.append('    <title>Mehlbrei</title>')
+    out.append('    <style>')
+    out.append('      html {height: 100%;width:100%;margin:0px;}')
+    out.append('      body {display: flex;height: 100%;width:100%;margin:0px;}')
+    out.append('      #topic_panel {height: 100%; overflow:scroll;flex-shrink:0;}')
+    out.append('      #main_panel {height: 100%; overflow:scroll;flex-grow:2;}')
+    out.append('      .topic_link {display:block;}')
+    out.append('      .empty-topic {opacity: 0.5;}')
+    out.append('      .alt-content {display:none;}')
+    out.append('      :target.alt-content {display:block;}')
+    out.append('      .message-block-container {border: 1px solid black;}')
+    out.append('      .message-block-meta {font-style: italic; font-weight: bolder;}')
+    out.append('      .message-block-content {white-space: pre;}')
+    out.append('    </style>')
+    out.append('  </head>')
+    out.append('  <body>')
+    out.append('    <div id="topic_panel">')
+    out.append('      <h1>Topics</h1>')
     for topic_root in all_topic_roots:
-        outfile.write('      <span class="topic_link'+(' empty-topic' if topic_root.non_diff_root_descendants == 0 else '')+'"><a href="#topic-'+str(topic_root.index)+'">'+html.escape(topic_root.msg.get('subject', '<no subject>'), quote=False)+'</a> ('+str(topic_root.non_diff_root_descendants)+' replies)</span>\n')
-    outfile.write('    </div>\n')
-    outfile.write('    <div id="main_panel">\n')
+        out.append('      <span class="topic_link'+(' empty-topic' if topic_root.non_diff_root_descendants == 0 else '')+'"><a href="#topic-'+str(topic_root.index)+'">'+html.escape(topic_root.msg.get('subject', '<no subject>'), quote=False)+'</a> ('+str(topic_root.non_diff_root_descendants)+' replies)</span>')
+    out.append('    </div>')
+    out.append('    <div id="main_panel">')
     for topic_root in all_topic_roots:
-        outfile.write('      <div class="alt-content" id="topic-'+str(topic_root.index)+'">\n')
+        out.append('      <div class="alt-content" id="topic-'+str(topic_root.index)+'">')
         printed_top_header = False
         printed_threads_header = False
         for block in topic_root.blocks.ranges:
             if block.start_pos_child < 0 and not printed_top_header:
-                outfile.write('        <h1>Top-posted messages (sorry this section looks like a mess)</h1>\n')
+                out.append('        <h1>Top-posted messages (sorry this section looks like a mess)</h1>')
                 printed_top_header = True
             if block.start_pos_child >= 0 and not printed_threads_header:
-                outfile.write('        <h1>Actual thread</h1>\n')
+                out.append('        <h1>Actual thread</h1>')
                 printed_threads_header = True
-            outfile.write('        <div class="message-block-container" style="margin-left:'+str(block.message.depth*4)+'em">\n')
-            outfile.write('          <div class="message-block-meta">'+html.escape(block.message.from_hdr, quote=False)+'</div>\n')
-            outfile.write('          <div class="message-block-content">'+html.escape(block.get_text(), quote=False)+'</div>\n')
-            outfile.write('        </div>\n')
-        outfile.write('      </div>\n')
-    outfile.write('    </div>\n')
-    outfile.write('  </body>\n')
-    outfile.write('</html>\n')
+            out.append('        <div class="message-block-container" style="margin-left:'+str(block.message.depth*4)+'em">')
+            out.append('          <div class="message-block-meta">'+html.escape(block.message.from_hdr, quote=False)+'</div>')
+            out.append('          <div class="message-block-content">'+html.escape(block.get_text(), quote=False)+'</div>')
+            out.append('        </div>')
+        out.append('      </div>')
+    out.append('    </div>')
+    out.append('  </body>')
+    out.append('</html>')
+
+    out = bytes('\n'.join(out), 'utf-8')
+    start_response("200 OK", [
+        ("Content-Type", "text/html; charset=utf-8"),
+        ("Content-Length", str(len(out)))
+    ])
+
+    return iter([out])