73 lines
2.5 KiB
Python
73 lines
2.5 KiB
Python
"""Miscellaneous helper functions and whatnot.
|
|
|
|
SPDX-FileCopyrightText: © 2021 Brian S. Stephan <bss@incorporeal.org>
|
|
SPDX-License-Identifier: AGPL-3.0-or-later
|
|
"""
|
|
import datetime
|
|
import logging
|
|
import os
|
|
import re
|
|
|
|
import markdown
|
|
from markupsafe import Markup
|
|
|
|
from incorporealcms.config import Config
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
def get_meta_str(md, key):
|
|
"""Provide the page's (parsed in Markup obj md) metadata for the specified key, or '' if unset."""
|
|
return " ".join(md.Meta.get(key)) if md.Meta.get(key) else ""
|
|
|
|
|
|
def init_md():
|
|
"""Initialize the Markdown parser.
|
|
|
|
This used to done at the app level in __init__, but extensions like footnotes apparently
|
|
assume the parser to only live for the length of parsing one document, and create double
|
|
footnote ref links if the one parser sees the same document multiple times.
|
|
"""
|
|
# initialize markdown parser from config, but include
|
|
# extensions our app depends on, like the meta extension
|
|
return markdown.Markdown(extensions=Config.MARKDOWN_EXTENSIONS + ['meta'],
|
|
extension_configs=Config.MARKDOWN_EXTENSION_CONFIGS)
|
|
|
|
|
|
def instance_resource_path_to_request_path(path):
|
|
"""Reverse a relative disk path to the path that would show up in a URL request."""
|
|
return '/' + re.sub(r'.md$', '', re.sub(r'index.md$', '', path))
|
|
|
|
|
|
def parse_md(path: str):
|
|
"""Given a file to parse, return file content and other derived data along with the md object.
|
|
|
|
Args:
|
|
path: the path to the file to render
|
|
"""
|
|
try:
|
|
logger.debug("opening path '%s'", path)
|
|
with open(path, 'r') as input_file:
|
|
mtime = datetime.datetime.fromtimestamp(os.path.getmtime(input_file.name), tz=datetime.timezone.utc)
|
|
entry = input_file.read()
|
|
logger.debug("path '%s' read", path)
|
|
md = init_md()
|
|
content = Markup(md.convert(entry))
|
|
except OSError:
|
|
logger.exception("path '%s' could not be opened!", path)
|
|
raise
|
|
except ValueError:
|
|
logger.exception("error parsing/rendering markdown!")
|
|
raise
|
|
except TypeError:
|
|
logger.exception("error loading/rendering markdown!")
|
|
raise
|
|
|
|
logger.debug("file metadata: %s", md.Meta)
|
|
|
|
page_name = get_meta_str(md, 'title') if md.Meta.get('title') else path
|
|
page_title = f'{page_name} - {Config.TITLE_SUFFIX}' if page_name else Config.TITLE_SUFFIX
|
|
logger.debug("title (potentially derived): %s", page_title)
|
|
|
|
return content, md, page_name, page_title, mtime
|