X-Git-Url: https://git.notmuchmail.org/git?a=blobdiff_plain;f=devel%2Fnmbug%2Fnmbug-status;h=f0809f193e108fb024982524a2a56ec1c3250173;hb=2bb906a6dd21fe109cc921590a512c1af7ff150d;hp=40e68962d111ee0ce35a5813daa544f7857e8d9b;hpb=e485b5bd1de1d514a35ab92d726240d2b46f99ab;p=notmuch
diff --git a/devel/nmbug/nmbug-status b/devel/nmbug/nmbug-status
index 40e68962..f0809f19 100755
--- a/devel/nmbug/nmbug-status
+++ b/devel/nmbug/nmbug-status
@@ -1,10 +1,30 @@
#!/usr/bin/python
#
# Copyright (c) 2011-2012 David Bremner
-# License: Same as notmuch
+#
# dependencies
# - python 2.6 for json
# - argparse; either python 2.7, or install separately
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see http://www.gnu.org/licenses/ .
+
+"""Generate HTML for one or more notmuch searches.
+
+Messages matching each search are grouped by thread. Each message
+that contains both a subject and message-id will have the displayed
+subject link to the Gmane view of the message.
+"""
from __future__ import print_function
from __future__ import unicode_literals
@@ -13,7 +33,6 @@ import codecs
import collections
import datetime
import email.utils
-import locale
try: # Python 3
from urllib.parse import quote
except ImportError: # Python 2
@@ -21,11 +40,13 @@ except ImportError: # Python 2
import json
import argparse
import os
+import re
import sys
import subprocess
+import xml.sax.saxutils
-_ENCODING = locale.getpreferredencoding() or sys.getdefaultencoding()
+_ENCODING = 'UTF-8'
_PAGES = {}
@@ -40,7 +61,7 @@ if not hasattr(collections, 'OrderedDict'): # Python 2.6 or earlier
super(_OrderedDict, self).__setitem__(key, value)
self._keys.append(key)
- def __values__(self):
+ def values(self):
for key in self._keys:
yield self[key]
@@ -88,7 +109,7 @@ class Page (object):
byte_stream = sys.stdout.buffer
except AttributeError: # Python 2
byte_stream = sys.stdout
- stream = codecs.getwriter(encoding='UTF-8')(stream=byte_stream)
+ stream = codecs.getwriter(encoding=_ENCODING)(stream=byte_stream)
self._write_header(views=views, stream=stream)
for view in views:
self._write_view(database=database, view=view, stream=stream)
@@ -168,24 +189,32 @@ class Page (object):
class HtmlPage (Page):
+ _slug_regexp = re.compile('\W+')
+
def _write_header(self, views, stream):
super(HtmlPage, self)._write_header(views=views, stream=stream)
stream.write('\n')
for view in views:
+ if 'id' not in view:
+ view['id'] = self._slug(view['title'])
stream.write(
- '- {title}
\n'.format(**view))
+ '- {title}
\n'.format(**view))
stream.write('
\n')
def _write_view_header(self, view, stream):
- stream.write('{title}
\n'.format(**view))
+ stream.write('{title}
\n'.format(**view))
+ stream.write('\n')
if 'comment' in view:
stream.write(view['comment'])
stream.write('\n')
for line in [
'The view is generated from the following query:',
- '
',
+ '
',
+ '',
+ ' ',
view['query-string'],
- '',
+ '
',
+ '
',
]:
stream.write(line)
stream.write('\n')
@@ -195,19 +224,22 @@ class HtmlPage (Page):
return
stream.write('\n')
for thread in threads:
+ stream.write(' \n')
for message_display_data in thread:
stream.write((
- '\n'
- ' {date} | \n'
- ' {message-id-term} | \n'
- '
\n'
- '\n'
- ' {from} | \n'
- ' {subject} | \n'
- '
\n'
+ ' \n'
+ ' {date} | \n'
+ ' {message-id-term} | \n'
+ '
\n'
+ ' \n'
+ ' {from} | \n'
+ ' {subject} | \n'
+ '
\n'
).format(**message_display_data))
+ stream.write(' \n')
if thread != threads[-1]:
- stream.write('
|
\n')
+ stream.write(
+ '
|
\n')
stream.write('
\n')
def _message_display_data(self, *args, **kwargs):
@@ -217,33 +249,20 @@ class HtmlPage (Page):
if 'subject' in display_data and 'message-id' in display_data:
d = {
'message-id': quote(display_data['message-id']),
- 'subject': display_data['subject'],
+ 'subject': xml.sax.saxutils.escape(display_data['subject']),
}
display_data['subject'] = (
'{subject}'
).format(**d)
+ for key in ['message-id', 'from']:
+ if key in display_data:
+ display_data[key] = xml.sax.saxutils.escape(display_data[key])
return (running_data, display_data)
+ def _slug(self, string):
+ return self._slug_regexp.sub('-', string)
-_PAGES['text'] = Page()
-_PAGES['html'] = HtmlPage(
- header='''
-
-
-
-Notmuch Patches
-
-
-Notmuch Patches
-Generated: {date}
-For more infomation see nmbug
-Views
-'''.format(date=datetime.datetime.utcnow().date()),
- footer='\n\n',
- )
-
-
-parser = argparse.ArgumentParser()
+parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument('--text', help='output plain text format',
action='store_true')
parser.add_argument('--config', help='load config from given file',
@@ -257,6 +276,82 @@ args = parser.parse_args()
config = read_config(path=args.config)
+header_template = config['meta'].get('header', '''
+
+
+
+ {title}
+
+
+
+{title}
+{blurb}
+
+Views
+''')
+
+footer_template = config['meta'].get('footer', '''
+
+Generated: {datetime}
+
+
+''')
+
+now = datetime.datetime.utcnow()
+context = {
+ 'date': now,
+ 'datetime': now.strftime('%Y-%m-%d %H:%M:%SZ'),
+ 'title': config['meta']['title'],
+ 'blurb': config['meta']['blurb'],
+ 'encoding': _ENCODING,
+ 'inter_message_padding': '0.25em',
+ 'border_radius': '0.5em',
+ }
+
+_PAGES['text'] = Page()
+_PAGES['html'] = HtmlPage(
+ header=header_template.format(**context),
+ footer=footer_template.format(**context),
+ )
+
if args.list_views:
for view in config['views']:
print(view['title'])