]> granicus.if.org Git - pgbouncer/commitdiff
Do not depend on Pandoc 2.0
authorMarco Nenciarini <marco.nenciarini@2ndquadrant.it>
Wed, 26 Jun 2019 13:38:48 +0000 (15:38 +0200)
committerPeter Eisentraut <peter@eisentraut.org>
Wed, 26 Jun 2019 19:56:01 +0000 (21:56 +0200)
Replace the Lua filter with one written in Python, so it can work with
older Pandoc versions.  Import pandocfilters.py package from Pandoc to
help with that.

.gitignore
.travis.yml
debian/control
doc/Makefile
doc/filter.lua [deleted file]
doc/filter.py [new file with mode: 0755]
doc/pandocfilters.py [new file with mode: 0644]

index 4e9ae891cc482099dedc382c3cf229fcab35fbe6..79216fe5f4d81f4b5b748ed96deaabb338e094d1 100644 (file)
@@ -20,4 +20,5 @@
 *.xml
 *.exe
 *.gz
+*.pyc
 *.swp
index 4d9531b25ad4a16c6cd778d6183778e2b4f0aa0d..3923ebe1ff95fc25615ed489c5c3ca84f951e57c 100644 (file)
@@ -9,9 +9,8 @@ addons:
       - libevent-dev
       - libudns-dev
       - lintian
-before_install:
-  - wget https://github.com/jgm/pandoc/releases/download/2.4/pandoc-2.4-1-amd64.deb
-  - sudo dpkg -i pandoc-2.4-1-amd64.deb
+      - pandoc
+      - python
 compiler:
   - clang
   - gcc
index c7931cfc51c3df3d92b4bfa2c2536a0ba048a07d..6d4d775b2066af82566ca3300837cea3ed8e109d 100644 (file)
@@ -3,7 +3,7 @@ Section: database
 Priority: extra
 Maintainer: Marko Kreen <markokr@gmail.com>
 Standards-Version: 3.6.2
-Build-Depends: debhelper (>= 9), make (>= 3.81), pandoc (>= 2.0),
+Build-Depends: debhelper (>= 9), make (>= 3.81), pandoc, python,
  libevent-dev (>= 2.0), libssl-dev (>= 1.0.1), libc-ares-dev (>= 1.7.0)
 
 Package: pgbouncer
index 9849ef8db623eb17284af52f64523d92d2ef508d..afd3b60077508d1b9db64c4499a7457850276cc0 100644 (file)
@@ -5,7 +5,8 @@ manpages = pgbouncer.1 pgbouncer.5
 dist_man_MANS = $(manpages)
 
 EXTRA_DIST = config.md usage.md Makefile $(manpages) \
-            frag-config-man.md frag-usage-man.md
+            frag-config-man.md frag-usage-man.md \
+            filter.py pandocfilters.py
 
 # make maintainer-clean removes those
 MAINTAINERCLEANFILES = $(manpages)
@@ -16,10 +17,10 @@ include $(abs_top_srcdir)/lib/mk/antimake.mk
 
 
 pgbouncer.1: frag-usage-man.md usage.md
-       $(PANDOC) --lua-filter=filter.lua -s -t man -o $@ $^
+       $(PANDOC) --filter=./filter.py -s -t man -o $@ $^
 
 pgbouncer.5: frag-config-man.md config.md
-       $(PANDOC) --lua-filter=filter.lua -s -t man -o $@ $^
+       $(PANDOC) --filter=./filter.py -s -t man -o $@ $^
 
 web:
        make -C ../../pgbouncer.github.io
diff --git a/doc/filter.lua b/doc/filter.lua
deleted file mode 100644 (file)
index 7b18c55..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-local text = require('text')
-
-function Header(el)
-  -- drop level-1 header
-  if el.level == 1 then
-    return {}
-  else
-    -- decrease level of all headers by 1
-    el.level = el.level - 1
-    -- convert level-1 headers to uppercase
-    if el.level == 1 then
-      return pandoc.walk_block(el, {
-        Str = function(el)
-          return pandoc.Str(text.upper(el.text))
-      end })
-    end
-  end
-end
diff --git a/doc/filter.py b/doc/filter.py
new file mode 100755 (executable)
index 0000000..97a9ec0
--- /dev/null
@@ -0,0 +1,26 @@
+#!/usr/bin/env python
+
+from pandocfilters import toJSONFilter, walk, Str, Header
+
+
+def caps(key, value, fmt, meta):
+    if key == "Str":
+        return Str(value.upper())
+
+
+def manify(key, value, fmt, meta):
+    if key == "Header":
+        # drop level-1 header
+        if value[0] == 1:
+            return []
+
+        # decrease level of all headers by 1
+        value[0] -= 1
+
+        # convert level-1 headers to uppercase
+        if value[0] == 1:
+            return Header(*walk(value, caps, fmt, meta))
+
+
+if __name__ == "__main__":
+    toJSONFilter(manify)
diff --git a/doc/pandocfilters.py b/doc/pandocfilters.py
new file mode 100644 (file)
index 0000000..81b7269
--- /dev/null
@@ -0,0 +1,288 @@
+# Author: John MacFarlane <jgm@berkeley.edu>
+# Copyright: (C) 2013 John MacFarlane
+# License: BSD3
+
+"""
+Functions to aid writing python scripts that process the pandoc
+AST serialized as JSON.
+"""
+
+import codecs
+import hashlib
+import io
+import json
+import os
+import sys
+
+
+# some utility-functions: make it easier to create your own filters
+
+
+def get_filename4code(module, content, ext=None):
+    """Generate filename based on content
+
+    The function ensures that the (temporary) directory exists, so that the
+    file can be written.
+
+    Example:
+        filename = get_filename4code("myfilter", code)
+    """
+    imagedir = module + "-images"
+    fn = hashlib.sha1(content.encode(sys.getfilesystemencoding())).hexdigest()
+    try:
+        os.mkdir(imagedir)
+        sys.stderr.write('Created directory ' + imagedir + '\n')
+    except OSError:
+        pass
+    if ext:
+        fn += "." + ext
+    return os.path.join(imagedir, fn)
+
+def get_value(kv, key, value = None):
+    """get value from the keyvalues (options)"""
+    res = []
+    for k, v in kv:
+        if k == key:
+            value = v
+        else:
+            res.append([k, v])
+    return value, res
+
+def get_caption(kv):
+    """get caption from the keyvalues (options)
+
+    Example:
+      if key == 'CodeBlock':
+        [[ident, classes, keyvals], code] = value
+        caption, typef, keyvals = get_caption(keyvals)
+        ...
+        return Para([Image([ident, [], keyvals], caption, [filename, typef])])
+    """
+    caption = []
+    typef = ""
+    value, res = get_value(kv, u"caption")
+    if value is not None:
+        caption = [Str(value)]
+        typef = "fig:"
+
+    return caption, typef, res
+
+
+def get_extension(format, default, **alternates):
+    """get the extension for the result, needs a default and some specialisations
+
+    Example:
+      filetype = get_extension(format, "png", html="svg", latex="eps")
+    """
+    try:
+        return alternates[format]
+    except KeyError:
+        return default
+
+# end of utilities
+
+
+def walk(x, action, format, meta):
+    """Walk a tree, applying an action to every object.
+    Returns a modified tree.  An action is a function of the form
+    `action(key, value, format, meta)`, where:
+
+    * `key` is the type of the pandoc object (e.g. 'Str', 'Para') `value` is
+    * the contents of the object (e.g. a string for 'Str', a list of
+      inline elements for 'Para')
+    * `format` is the target output format (as supplied by the
+      `format` argument of `walk`)
+    * `meta` is the document's metadata
+
+    The return of an action is either:
+
+    * `None`: this means that the object should remain unchanged
+    * a pandoc object: this will replace the original object
+    * a list of pandoc objects: these will replace the original object; the
+      list is merged with the neighbors of the orignal objects (spliced into
+      the list the original object belongs to); returning an empty list deletes
+      the object
+    """
+    if isinstance(x, list):
+        array = []
+        for item in x:
+            if isinstance(item, dict) and 't' in item:
+                res = action(item['t'],
+                             item['c'] if 'c' in item else None, format, meta)
+                if res is None:
+                    array.append(walk(item, action, format, meta))
+                elif isinstance(res, list):
+                    for z in res:
+                        array.append(walk(z, action, format, meta))
+                else:
+                    array.append(walk(res, action, format, meta))
+            else:
+                array.append(walk(item, action, format, meta))
+        return array
+    elif isinstance(x, dict):
+        for k in x:
+            x[k] = walk(x[k], action, format, meta)
+        return x
+    else:
+        return x
+
+def toJSONFilter(action):
+    """Like `toJSONFilters`, but takes a single action as argument.
+    """
+    toJSONFilters([action])
+
+
+def toJSONFilters(actions):
+    """Generate a JSON-to-JSON filter from stdin to stdout
+
+    The filter:
+
+    * reads a JSON-formatted pandoc document from stdin
+    * transforms it by walking the tree and performing the actions
+    * returns a new JSON-formatted pandoc document to stdout
+
+    The argument `actions` is a list of functions of the form
+    `action(key, value, format, meta)`, as described in more
+    detail under `walk`.
+
+    This function calls `applyJSONFilters`, with the `format`
+    argument provided by the first command-line argument,
+    if present.  (Pandoc sets this by default when calling
+    filters.)
+    """
+    try:
+        input_stream = io.TextIOWrapper(sys.stdin.buffer, encoding='utf-8')
+    except AttributeError:
+        # Python 2 does not have sys.stdin.buffer.
+        # REF: https://stackoverflow.com/questions/2467928/python-unicodeencode
+        input_stream = codecs.getreader("utf-8")(sys.stdin)
+
+    source = input_stream.read()
+    if len(sys.argv) > 1:
+        format = sys.argv[1]
+    else:
+        format = ""
+
+    sys.stdout.write(applyJSONFilters(actions, source, format))
+
+def applyJSONFilters(actions, source, format=""):
+    """Walk through JSON structure and apply filters
+
+    This:
+
+    * reads a JSON-formatted pandoc document from a source string
+    * transforms it by walking the tree and performing the actions
+    * returns a new JSON-formatted pandoc document as a string
+
+    The `actions` argument is a list of functions (see `walk`
+    for a full description).
+
+    The argument `source` is a string encoded JSON object.
+
+    The argument `format` is a string describing the output format.
+
+    Returns a the new JSON-formatted pandoc document.
+    """
+
+    doc = json.loads(source)
+
+    if 'meta' in doc:
+        meta = doc['meta']
+    elif doc[0]:  # old API
+        meta = doc[0]['unMeta']
+    else:
+        meta = {}
+    altered = doc
+    for action in actions:
+        altered = walk(altered, action, format, meta)
+
+    return json.dumps(altered)
+
+
+def stringify(x):
+    """Walks the tree x and returns concatenated string content,
+    leaving out all formatting.
+    """
+    result = []
+
+    def go(key, val, format, meta):
+        if key in ['Str', 'MetaString']:
+            result.append(val)
+        elif key == 'Code':
+            result.append(val[1])
+        elif key == 'Math':
+            result.append(val[1])
+        elif key == 'LineBreak':
+            result.append(" ")
+        elif key == 'SoftBreak':
+            result.append(" ")
+        elif key == 'Space':
+            result.append(" ")
+
+    walk(x, go, "", {})
+    return ''.join(result)
+
+
+def attributes(attrs):
+    """Returns an attribute list, constructed from the
+    dictionary attrs.
+    """
+    attrs = attrs or {}
+    ident = attrs.get("id", "")
+    classes = attrs.get("classes", [])
+    keyvals = [[x, attrs[x]] for x in attrs if (x != "classes" and x != "id")]
+    return [ident, classes, keyvals]
+
+
+def elt(eltType, numargs):
+    def fun(*args):
+        lenargs = len(args)
+        if lenargs != numargs:
+            raise ValueError(eltType + ' expects ' + str(numargs) +
+                             ' arguments, but given ' + str(lenargs))
+        if numargs == 0:
+            xs = []
+        elif len(args) == 1:
+            xs = args[0]
+        else:
+            xs = list(args)
+        return {'t': eltType, 'c': xs}
+    return fun
+
+# Constructors for block elements
+
+Plain = elt('Plain', 1)
+Para = elt('Para', 1)
+CodeBlock = elt('CodeBlock', 2)
+RawBlock = elt('RawBlock', 2)
+BlockQuote = elt('BlockQuote', 1)
+OrderedList = elt('OrderedList', 2)
+BulletList = elt('BulletList', 1)
+DefinitionList = elt('DefinitionList', 1)
+Header = elt('Header', 3)
+HorizontalRule = elt('HorizontalRule', 0)
+Table = elt('Table', 5)
+Div = elt('Div', 2)
+Null = elt('Null', 0)
+
+# Constructors for inline elements
+
+Str = elt('Str', 1)
+Emph = elt('Emph', 1)
+Strong = elt('Strong', 1)
+Strikeout = elt('Strikeout', 1)
+Superscript = elt('Superscript', 1)
+Subscript = elt('Subscript', 1)
+SmallCaps = elt('SmallCaps', 1)
+Quoted = elt('Quoted', 2)
+Cite = elt('Cite', 2)
+Code = elt('Code', 2)
+Space = elt('Space', 0)
+LineBreak = elt('LineBreak', 0)
+Math = elt('Math', 2)
+RawInline = elt('RawInline', 2)
+Link = elt('Link', 3)
+Image = elt('Image', 3)
+Note = elt('Note', 1)
+SoftBreak = elt('SoftBreak', 0)
+Span = elt('Span', 2)