Skip to content

Commit

Permalink
Merge pull request #940 from jeffrimko/master
Browse files Browse the repository at this point in the history
AsciiDoc: Support both legacy and asciidoctor via CLI subprocess
  • Loading branch information
justinmayer committed Jan 2, 2018
2 parents 83bede1 + ad6d407 commit 8de8e84
Show file tree
Hide file tree
Showing 6 changed files with 88 additions and 325 deletions.
20 changes: 10 additions & 10 deletions asciidoc_reader/README.rst
Original file line number Diff line number Diff line change
@@ -1,30 +1,30 @@
AsciiDoc Reader
###############

This plugin allows you to use `AsciiDoc <http://www.methods.co.nz/asciidoc/>`_
to write your posts. File extension should be ``.asc``, ``.adoc``,
This plugin allows you to use `AsciiDoc <http://www.methods.co.nz/asciidoc/>`_
to write your posts. File extension should be ``.asc``, ``.adoc``,
or ``.asciidoc``.

Dependency
----------

If you want to use AsciiDoc you need to install it from `source
<http://www.methods.co.nz/asciidoc/INSTALL.html>`_ or use your operating
system's package manager.
There are two command line utilities commonly used to render AsciiDoc:
``asciidoc`` and ``asciidoctor``. One of the two will need to be installed and
on the PATH.

**Note**: AsciiDoc does not work with Python 3, so you should be using Python 2.
**Note**: The ``asciidoctor`` utility is recommended since the original
``asciidoc`` is no longer maintained.

Settings
--------

======================================== =======================================================
Setting name (followed by default value) What does it do?
======================================== =======================================================
``ASCIIDOC_CMD = asciidoc`` Selects which utility to use for rendering. Will
autodetect utility if not provided.
``ASCIIDOC_OPTIONS = []`` A list of options to pass to AsciiDoc. See the `manpage
<http://www.methods.co.nz/asciidoc/manpage.html>`_.
``ASCIIDOC_BACKEND = 'html5'`` Backend format for output. See the `documentation
<http://www.methods.co.nz/asciidoc/userguide.html#X5>`_
for possible values.
======================================== =======================================================

Example file header
Expand All @@ -45,5 +45,5 @@ Following the `example <https://github.com/getpelican/pelican/blob/master/docs/c
:summary: Short version for index and feeds
== title level 2
and so on...
96 changes: 58 additions & 38 deletions asciidoc_reader/asciidoc_reader.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,61 +3,81 @@
AsciiDoc Reader
===============
This plugin allows you to use AsciiDoc to write your posts.
This plugin allows you to use AsciiDoc to write your posts.
File extension should be ``.asc``, ``.adoc``, or ``asciidoc``.
"""

from pelican.readers import BaseReader
from pelican.utils import pelican_open
from pelican import signals
import six
import os
import re
import subprocess

try:
# asciidocapi won't import on Py3
from .asciidocapi import AsciiDocAPI, AsciiDocError
# AsciiDocAPI class checks for asciidoc.py
AsciiDocAPI()
except:
asciidoc_enabled = False
else:
asciidoc_enabled = True
def call(cmd):
"""Calls a CLI command and returns the stdout as string."""
return subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True).communicate()[0].decode('utf-8')

def default():
"""Attempt to find the default AsciiDoc utility."""
for cmd in ALLOWED_CMDS:
if len(call(cmd + " --help")):
return cmd

ALLOWED_CMDS = ["asciidoc", "asciidoctor"]

ENABLED = None != default()

class AsciiDocReader(BaseReader):
"""Reader for AsciiDoc files"""
"""Reader for AsciiDoc files."""

enabled = asciidoc_enabled
enabled = ENABLED
file_extensions = ['asc', 'adoc', 'asciidoc']
default_options = ["--no-header-footer", "-a newline=\\n"]
default_backend = 'html5'
default_options = ['--no-header-footer']

def read(self, source_path):
"""Parse content and metadata of asciidoc files"""
from cStringIO import StringIO
with pelican_open(source_path) as source:
text = StringIO(source.encode('utf8'))
content = StringIO()
ad = AsciiDocAPI()

options = self.settings.get('ASCIIDOC_OPTIONS', [])
options = self.default_options + options
for o in options:
ad.options(*o.split())
"""Parse content and metadata of AsciiDoc files."""
cmd = self._get_cmd()
content = ""
if cmd:
optlist = self.settings.get('ASCIIDOC_OPTIONS', []) + self.default_options
options = " ".join(optlist)
content = call("%s %s -o - %s" % (cmd, options, source_path))
metadata = self._read_metadata(source_path)
return content, metadata

backend = self.settings.get('ASCIIDOC_BACKEND', self.default_backend)
ad.execute(text, content, backend=backend)
content = content.getvalue().decode('utf8')
def _get_cmd(self):
"""Returns the AsciiDoc utility command to use for rendering or None if
one cannot be found."""
if self.settings.get('ASCIIDOC_CMD') in ALLOWED_CMDS:
return self.settings.get('ASCIIDOC_CMD')
return default()

def _read_metadata(self, source_path):
"""Parses the AsciiDoc file at the given `source_path` and returns found
metadata."""
metadata = {}
for name, value in ad.asciidoc.document.attributes.items():
if value is None:
continue
name = name.lower()
metadata[name] = self.process_metadata(name, six.text_type(value))
if 'doctitle' in metadata:
metadata['title'] = metadata['doctitle']
return content, metadata
with open(source_path) as fi:
prev = ""
for line in fi.readlines():
# Parse for doc title.
if 'title' not in metadata.keys():
title = ""
if line.startswith("= "):
title = line[2:].strip()
elif line.count("=") == len(prev.strip()):
title = prev.strip()
if title:
metadata['title'] = self.process_metadata('title', title)

# Parse for other metadata.
regexp = re.compile(r"^:[A-z]+:\s*[A-z0-9]")
if regexp.search(line):
toks = line.split(":", 2)
key = toks[1].strip().lower()
val = toks[2].strip()
metadata[key] = self.process_metadata(key, val)
prev = line
return metadata

def add_reader(readers):
for ext in AsciiDocReader.file_extensions:
Expand Down
Loading

0 comments on commit 8de8e84

Please sign in to comment.