diff options
| -rw-r--r-- | Containerfile | 6 | ||||
| -rw-r--r-- | about-filter.py | 72 |
2 files changed, 76 insertions, 2 deletions
diff --git a/Containerfile b/Containerfile index e15c99c..b517a28 100644 --- a/Containerfile +++ b/Containerfile @@ -1,6 +1,6 @@ ARG DEBIAN_VERSION=trixie ARG CGIT_VERSION=1.3.1 -ARG IMAGE_REVISION=1 +ARG IMAGE_REVISION=2 FROM debian:${DEBIAN_VERSION}-slim AS builder @@ -46,7 +46,7 @@ RUN make install \ FROM debian:${DEBIAN_VERSION}-slim ARG CGIT_VERSION=1.3.1 -ARG IMAGE_REVISION=1 +ARG IMAGE_REVISION=2 LABEL org.opencontainers.image.title="cgit" \ org.opencontainers.image.version="${CGIT_VERSION}-r${IMAGE_REVISION}" @@ -54,6 +54,7 @@ LABEL org.opencontainers.image.title="cgit" \ RUN apt-get update \ && apt-get install --no-install-recommends -y \ busybox-static \ + cmark-gfm \ python3-pygments \ tini \ zlib1g \ @@ -61,6 +62,7 @@ RUN apt-get update \ COPY --from=builder /out/www /www +COPY --chmod=0555 about-filter.py /usr/libexec/cgit/about-filter.py COPY --chmod=0555 syntax-highlighting.py /usr/libexec/cgit/syntax-highlighting.py RUN mkdir -p \ diff --git a/about-filter.py b/about-filter.py new file mode 100644 index 0000000..5e97bbe --- /dev/null +++ b/about-filter.py @@ -0,0 +1,72 @@ +#!/usr/bin/env python3 + +"""Render cgit repository READMEs as safe HTML.""" + +import html +import os +import subprocess +import sys + + +MARKDOWN_EXTENSIONS = (".md", ".markdown") +CMARK_COMMAND = ( + "/usr/bin/cmark-gfm", + "--validate-utf8", + "--extension", + "table", + "--extension", + "autolink", + "--extension", + "strikethrough", + "--extension", + "tasklist", +) + +STYLE = """<style> +.markdown-body { line-height: 1.6; overflow-wrap: anywhere; } +.markdown-body img { max-width: 100%; } +.markdown-body pre { overflow-x: auto; padding: 1em; background: rgb(255 255 255 / 6%); } +.markdown-body code { padding: .15em .3em; background: rgb(255 255 255 / 8%); } +.markdown-body pre code { padding: 0; background: none; } +.markdown-body blockquote { margin-left: 0; padding-left: 1em; color: #aaa; border-left: .25em solid #555; } +.markdown-body table { display: block; max-width: 100%; overflow-x: auto; border-collapse: collapse; } +.markdown-body th, .markdown-body td { padding: .4em .8em; border: 1px solid #555; } +.markdown-body input[type="checkbox"] { margin-right: .4em; } +</style> +""" + + +def render_markdown(source: bytes) -> bytes: + """Render Markdown with cmark-gfm's safe defaults.""" + result = subprocess.run( + CMARK_COMMAND, + input=source, + stdout=subprocess.PIPE, + check=True, + ) + return result.stdout + + +def render_plain_text(source: bytes) -> bytes: + """Return arbitrary input as escaped, readable text.""" + text = source.decode("utf-8", errors="replace") + return f"<pre>{html.escape(text)}</pre>\n".encode() + + +def main() -> None: + filename = sys.argv[1] if len(sys.argv) > 1 else "" + source = sys.stdin.buffer.read() + + if os.path.splitext(filename)[1].lower() in MARKDOWN_EXTENSIONS: + rendered = render_markdown(source) + else: + rendered = render_plain_text(source) + + sys.stdout.buffer.write(STYLE.encode()) + sys.stdout.buffer.write(b'<div class="markdown-body">\n') + sys.stdout.buffer.write(rendered) + sys.stdout.buffer.write(b"</div>\n") + + +if __name__ == "__main__": + main() |
