[python-debian/master] examples/deb822/: add new example render-dctrl

Stefano Zacchiroli zack at upsilon.cc
Sun Apr 26 16:10:19 UTC 2009


---
 debian/changelog             |    7 ++
 examples/deb822/render-dctrl |  170 ++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 177 insertions(+), 0 deletions(-)
 create mode 100755 examples/deb822/render-dctrl

diff --git a/debian/changelog b/debian/changelog
index 4ef3d7d..8788db4 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,10 @@
+python-debian (0.1.14) UNRELEASED; urgency=low
+
+  * examples/deb822/: add new example render-dctrl, to render packages in
+    a dctrl-tools pipeline (using Markdown as long description syntax)
+
+ -- Stefano Zacchiroli <zack at debian.org>  Sun, 26 Apr 2009 18:08:50 +0200
+
 python-debian (0.1.13) unstable; urgency=low
 
   [ John Wright ]
diff --git a/examples/deb822/render-dctrl b/examples/deb822/render-dctrl
new file mode 100755
index 0000000..19d48d2
--- /dev/null
+++ b/examples/deb822/render-dctrl
@@ -0,0 +1,170 @@
+#!/usr/bin/python
+
+# render-dctrl
+# Copyright (C) 2009 Stefano Zacchiroli <zack at debian.org>
+#
+# 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.
+
+# Requirements (Debian packages): python-debian python-markdown
+
+usage = """Usage: render-dctrl [OPTION ...] [FILE ...]
+
+Render a 822-like listing of Debian packages (AKA "Packages" file) to
+XHTML, rendering (long) descriptions as Markdown text.  Render text
+coming from FILEs, if given, or from standard input otherwise. Typical
+usage is within a dctrl-tools pipeline, example:
+
+  grep-available -s Package,Depends,Description ocaml | render-dctrl > foo.html
+
+Warning: beware of #525525 and thus avoid using "-s Description" alone."""
+
+import re
+import string
+import sys
+from debian_bundle import deb822
+from markdown import markdown
+from optparse import OptionParser
+
+options = None		# global, for cmdline options
+
+css = """
+body { font-family: sans-serif; }
+dt {
+  font-weight: bold;
+}
+dd {
+  margin-bottom: 5pt;
+}
+div.package {
+  border: solid 1pt;
+  margin-top: 10pt;
+  padding-left: 2pt;
+  padding-right: 2pt;
+}
+.raw {
+  font-family: monospace;
+  background: #ddd;
+  padding-left: 2pt;
+  padding-right: 2pt;
+}
+.shortdesc {
+  text-decoration: underline;
+  margin-bottom: 5pt;
+  display: block;
+}
+.longdesc {
+  background: #eee;
+}
+span.package {
+  font-family: monospace;
+  font-size: 110%;
+}
+.uid {
+  float: right;
+  font-size: x-small;
+  padding-right: 10pt;
+}
+"""
+html_header = """<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+  <head>
+    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+    <style type="text/css">%s</style>
+  </head>
+  <body>
+""" % css
+html_trailer = """  </body>
+</html>
+"""
+
+mdwn_list_line = re.compile(r'^(\s*)[\*\+\-]')	# Markdown list item line
+# mdwn_head_line = re.compile(r'^(\s*)#')	# Markdown header
+padding = re.compile(r'^(\s*)')
+
+def get_indent(s):
+    m = padding.match(s)
+    if m:
+        return len(m.group(1))
+    else:
+        return 0
+
+def render_longdesc(lines):
+    print '<div class="longdesc">'
+    lines = map(lambda s: s[1:], lines)	# strip 822 heading space
+    curpara, paragraphs = [], []
+    inlist, listindent = False, 0
+    store_para = lambda: paragraphs.append(string.join(curpara, '\n') + '\n')
+
+    for l in lines:	# recognize Markdown paragraphs
+        if l.rstrip() == '.':	# RULE 1: split paragraphs at Debian's "."
+            store_para()            
+            curpara, inlist, listindent = [], False, 0
+        else:
+            m = mdwn_list_line.match(l)
+            if not inlist and m and curpara:
+                # RULE 2: handle list item *not* at paragraph beginning
+                store_para()	# => start a new paragraph
+                curpara, inlist, listindent = [l], True, get_indent(l)
+            elif inlist and get_indent(l) <= listindent:
+                # RULE 3: leave list when indentation decreases
+                store_para()	# => start a new paragraph
+                curpara, inlist, listindent = [l], False, 0
+            else:
+                curpara.append(l)
+
+    for p in paragraphs:	# render paragraphs
+        print markdown(p)
+    print '</div>'
+
+def render_field(field, val):
+    field = field.lower()
+    print '<dt>%s</dt>' % field
+    print '<dd class="%s">' % field
+    if field == 'description':
+        lines = val.split('\n')
+        print '<span class="shortdesc">%s</span>' % lines[0]
+        render_longdesc(lines[1:])
+    elif field == 'package':
+        print '<a href="#%s" class="uid">id</a>' % val
+        print '<span id="%s" class="package">%s</span>' % (val, val)
+    elif field in []:	# fields not to be typeset as "raw"
+        print '<span class="%s">%s</span>' % (field, val)
+    else:
+        print '<span class="raw">%s</span>' % val
+    print '</dd>'
+
+def render_file(f):
+    global options, html_header, html_trailer
+
+    if options.print_header:
+        print html_header
+    for pkg in deb822.Packages.iter_paragraphs(f):
+        print '<div class="package">'
+        print '<dl class="fields">'
+        for (field, val) in pkg.iteritems():
+            render_field(field, val)
+        print '</dl>'
+        print '</div>\n'
+    if options.print_header:
+        print html_trailer
+
+def main():
+    global options, usage
+
+    parser = OptionParser(usage=usage)
+    parser.add_option("-n", "--no-headers",
+                      action="store_false", dest="print_header", default=True,
+                      help="suppress printing of HTML header/trailer")
+    (options, args) = parser.parse_args()
+    if len(args):
+        for fname in args:
+            render_file(open(fname))
+    else:
+        render_file(sys.stdin)
+
+if __name__ == '__main__':
+    main()
-- 
1.5.6.5




More information about the pkg-python-debian-commits mailing list