#!/usr/bin/env python3 import sys import re from glob import glob from ipo import read, write, map, dictmap, starstarmap, join, sort, ipo from functools import partial from markdown import markdown import strictyaml md_to_html = join("\n") | ipo(markdown) yaml_to_dict = join("\n") | ipo(strictyaml.load) | ipo(lambda x: x.data) @ipo def parted(data, regex): """ Two parts of data, delimited by the first element on which regex fullmatches. If a delimiter is found, the second part is an iterator over the remaining elements. Else it is None. """ first = [] it = iter(data) try: while True: item = next(it) if re.fullmatch(regex, item): break first.append(item) except StopIteration: return (first, None) return (first, it) LIST_ITEM_TEMPLATE = """
  • {title}
    {summary}
  • """ def blog_page_template(): with open("blog.html") as fh: return fh.read() # FIXME what a mess def blog_page(file, read_body=True): """ Keep the file open if you want to be able to read the body. Good: >>> with open(…) as file: >>> metadata, body = blog_page(file) >>> [smthng(line) for line in body] >>> print("\n".join(hello)) Bad: >>> with open(…) as file: >>> metadata, body = blog_page(file) >>> hello = (smthng(line) for line in body) # Lazy generator, the body wasn't read from file yet >>> print("\n".join(hello)) """ if isinstance(file, str): assert not read_body, "Can't read body when giving a filename, need a file for that." filename = file file = open(filename) else: filename = None try: metadata_yaml, body_md = read(file) | parted("---+") metadata = { **(metadata_yaml | yaml_to_dict), } if not read_body: metadata["path"] = re.sub(r".md$", "", filename) body = ( body_md | md_to_html(extensions=["abbr", "toc", "smarty", "fenced_code", "codehilite"]) if read_body else None ) return (metadata, body) finally: if filename: file.close() def safe_metadata(metadata): return { k: ( v if k in ("published", "path") else markdown(v, extensions=["smarty"]).replace("

    ", "").replace("

    ", "") ) for k, v in metadata.items() } if sys.argv[1] == "--index": blog_post_list = ( glob("blog/*.md") | map(lambda filename: { **blog_page(filename, read_body=False)[0], }) | sort(key=lambda x: x["published"]) | map(safe_metadata) | map(lambda metadata: LIST_ITEM_TEMPLATE.format(**metadata)) | join("") ) with open(sys.argv[2]) as file_in, open(sys.argv[3], "w") as file_out: file_in.read().format(blog_posts=blog_post_list) | write(file=file_out) else: with open(sys.argv[1]) as file_in, open(sys.argv[2], "w") as file_out: metadata, body = blog_page(file_in) blog_page_template().format(**safe_metadata(metadata), body=body) | write(file=file_out)