tools.py 3.92 KB

from os import path
import subprocess
import logging

import yaml
# import markdown
import mistune
from pygments import highlight
from pygments.lexers import get_lexer_by_name
from pygments.formatters import html

# setup logger for this module
logger = logging.getLogger(__name__)


# ---------------------------------------------------------------------------
class HighlightRenderer(mistune.Renderer):
    def block_code(self, code, lang=None):
        if lang is None:
            return f'\n<pre><code>{mistune.escape(code)}</code></pre>\n'
        else:
            lexer = get_lexer_by_name(lang, stripall=True)
            formatter = html.HtmlFormatter()
            return highlight(code, lexer, formatter)

    def image(self, src, title, text):
        src = 'FIXME'  # FIXME
        return super().image(src, title, text)

renderer = HighlightRenderer(hard_wrap=True)
markdown = mistune.Markdown(renderer=renderer)


# ---------------------------------------------------------------------------
# load data from yaml file
# ---------------------------------------------------------------------------
def load_yaml(filename, default=None):
    try:
        f = open(path.expanduser(filename), 'r', encoding='utf-8')
    except IOError:
        logger.error(f'Can\'t open file "{filename}"')
        return default
    else:
        with f:
            try:
                return yaml.load(f)
            except yaml.YAMLError as e:
                mark = e.problem_mark
                logger.error('In YAML file "{0}" near line {1}, column {2}.'.format(filename, mark.line, mark.column+1))
                return default

# ---------------------------------------------------------------------------
# Runs a script and returns its stdout parsed as yaml, or None on error.
# ---------------------------------------------------------------------------
def run_script(script, stdin='', timeout=5):
    script = path.expanduser(script)
    try:
        p = subprocess.run([script],
            input=stdin,
            stdout=subprocess.PIPE,
            stderr=subprocess.STDOUT,
            universal_newlines=True,
            timeout=timeout,
            )
    except FileNotFoundError:
        logger.error(f'Script "{script}" not found.')
    except PermissionError:
        logger.error(f'Script "{script}" not executable. Wrong permissions?')
    except subprocess.TimeoutExpired:
        logger.error(f'Timeout {timeout}s exceeded while running "{script}".')
    else:
        if p.returncode != 0:
            logger.error(f'Script "{script}" returned error code {p.returncode}.')
        else:
            try:
                output = yaml.load(p.stdout)
            except:
                logger.error('Error parsing yaml output of "{script}"')
            else:
                return output

# ---------------------------------------------------------------------------
def md_to_html(text, q=None):
    return markdown(text)

# def md_to_html(text, ref=None, files={}):
#     if ref is not None:
#         # given q['ref'] and q['files'] replaces references to files by a
#         # GET to /file?ref=???;name=???
#         for k in files:
#             text = text.replace(k, '/file?ref={};name={}'.format(ref, k))
#     return markdown.markdown(text, extensions=[
#         'markdown.extensions.tables',
#         'markdown.extensions.fenced_code',
#         'markdown.extensions.codehilite',
#         'markdown.extensions.def_list',
#         'markdown.extensions.sane_lists'
#     ])

# ---------------------------------------------------------------------------
# def md_to_html_review(text, q):
#     for k,f in q['files'].items():
#         text = text.replace(k, '/absfile?name={}'.format(q['files'][k]))
#     return markdown.markdown(text, extensions=[
#         'markdown.extensions.tables',
#         'markdown.extensions.fenced_code',
#         'markdown.extensions.codehilite',
#         'markdown.extensions.def_list',
#         'markdown.extensions.sane_lists'
#     ])