blob: 9ac0c61a053523b33085b30001af41f612c83232 [file] [log] [blame]
#!/usr/bin/python -B
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
# -- Pelican plugin that processes ezt template Markdown through ezt and then GitHub Flavored Markdown.
import sys
import io
import os
import traceback
import re
import ezt
import pelican.plugins.signals
import pelican.readers
import pelican.settings
# The gfm plugin should have been loaded before this one.
### TODO: maybe can sort gfm to the front of the list.
import gfm
METADATA_RE = re.compile(r'\[{\s*(?P<meta>[-._:a-zA-Z0-9\[\]]+)\s*}\]')
class ASFTemplateReader(ezt.Reader):
"""Enables inserts relative to the template we loaded."""
def __init__(self, source_path, text):
self.source_dir, self.fname = os.path.split(source_path)
self.text = text
def read_other(self, relative):
return ezt._FileReader(os.path.join(self.source_dir, relative)) # pylint: disable=protected-access
def filename(self):
return self.fname
class ASFReader(gfm.GFMReader):
"""GFM-flavored Reader for the Pelican system that adds ASF data and ezt
generation prior to processing the GFM
def add_data(self, text, metadata):
"Mix in ASF data as metadata"
asf_metadata = self.settings.get('ASF_DATA', { }).get('metadata')
if asf_metadata:
# insert any direct references
m = 1
while m:
m =
if m:
this_data =
format_string = '{{{0}}}'.format(this_data)
new_string = format_string.format(**metadata)
print(f'{{{{{}}}}} -> {new_string}')
except Exception:
# the data expression was not found
new_string = format_string
print(f'{{{{{}}}}} is not found')
text = re.sub(METADATA_RE, new_string, text, count=1)
return text, metadata
def read(self, source_path):
"Read metadata and content, process content as ezt template, then render into HTML."
# read content with embedded ezt - use GFMReader
text, metadata = super().read_source(source_path)
assert text
assert metadata
# supplement metadata with ASFData if available
text, metadata = self.add_data(text, metadata)
# prepare text as an ezt template
# compress_whitespace=0 is required as blank lines and indentation have meaning in markdown.
template = ezt.Template(compress_whitespace=0)
assert template
reader = ASFTemplateReader(source_path, text)
template.parse(reader, base_format=ezt.FORMAT_HTML)
# generate content from ezt template with metadata
fp = io.StringIO()
template.generate(fp, metadata)
# Render the markdown into HTML
content = super().render(fp.getvalue().encode('utf-8')).decode('utf-8')
assert content
except Exception:
print('-----', file=sys.stderr)
print('ERROR: %s' % (source_path), file=sys.stderr)
return content, metadata
# The following are required or ezmd files are not read instead they are static.
# For direct subclasses of BaseReader like GFMReader the following two
# callables are optional if the class includes enabled=True and file_extenaions.
def add_readers(readers):
readers.reader_classes['ezmd'] = ASFReader
def register():