#!/usr/bin/env python3 ''' Transforms a file into a web-servable file. In most cases this entails either + just symlinking, or + transforming a page to html ''' import sys import os import html import subprocess import yaml def read(path): with open(path) as f: return f.read() def write(path, text): with open(path, 'w') as f: f.write(text) script_dir = os.path.dirname(__file__) base_dir = os.path.split(script_dir)[0] template_dir = os.path.join(base_dir, 'template') template_base_file = os.path.join(template_dir, 'base.html') template_base = read(template_base_file) site_dir = os.path.join(base_dir, 'site') def pandoc(filename): proc = subprocess.run(['pandoc', '-f', 'markdown+smart', filename], stdout=subprocess.PIPE) return proc.stdout.decode('utf-8').strip() def pandoc_stdin(text): out = subprocess.Popen( ['pandoc', '-f', 'markdown+smart'], stdin=subprocess.PIPE, stdout=subprocess.PIPE).communicate(text.encode('utf-8'))[0] return out.decode('utf-8').strip() def extract_markdown_title(filename): with open(filename) as f: for line in f: if line.startswith('# '): return line[2:].strip() if filename.endswith('.md'): return os.path.basename(filename)[:-3] def extract_markdown_abstract(filename): state = 0 with open(filename) as f: for line in f: if state == 0 and line == '---\n': state = 1 yaml_block = '' elif state == 1: if line == '---\n': y = yaml.load(yaml_block) if y is None: return None else: return y.get('abstract').strip().replace('\n', ' ') else: yaml_block += line def markdown_to_html(input_file, output_dir): title = extract_markdown_title(input_file) title = html.escape(title) common = os.path.commonpath([input_file, output_dir]) relpath = os.path.relpath(input_file, start=common) # Special cases if relpath == 'site/misc/index.md': top = read(input_file) pages = [] for path, subdirs, subfiles in os.walk(site_dir): dir = path if dir.startswith('./'): dir = dir[1:] if dir.startswith('/site'): dir = dir[5:] if 'index.md' in subfiles: pages.append((dir + '/', os.path.normpath(os.path.join(base_dir, path, 'index.md')))) for name in subfiles: if name.endswith('.md') and name != 'index.md': uri = name[:-3] pages.append((dir + '/' + uri, os.path.normpath(os.path.join(base_dir, path, name)))) builtins = ['/', '/about/', '/about/niels', '/misc/', '/404'] pages = filter(lambda t: t[0] not in builtins, pages) pages_new = [] for page in pages: url, path = page ptitle = extract_markdown_title(path) pabstract = extract_markdown_abstract(path) pages_new.append((ptitle, pabstract, url, path)) pages_new.append(('Potators', 'Do not look.', '/potator/', '/potator/')) pages_new.sort() md = '' for page in pages_new: ptitle, pabstract, url, _ = page if pabstract is None: pabstract = '(No description)' md += '[{}]({})\n ~ {}\n\n'.format(ptitle, url, pabstract) bottom = md content = pandoc_stdin(top + '\n' + bottom) else: content = pandoc(input_file) html_out = template_base.format(title=title, content=content) output_file = os.path.join( output_dir, os.path.splitext(os.path.basename(input_file))[0] + '.html') write(output_file, html_out) def symlink_relative(input_file, output_dir): in_path_abs = os.path.abspath(input_file) os.chdir(output_dir) in_path_rel = os.path.relpath(in_path_abs) output_file = os.path.basename(input_file) os.symlink(in_path_rel, output_file) def get_extension(filename): _, extension = os.path.splitext(filename) extension = extension[1:] return extension def transform(input_file, output_dir): extension = get_extension(input_file) actions = { 'md': lambda: markdown_to_html(input_file, output_dir) } try: action = actions[extension] except KeyError: action = lambda: symlink_relative(input_file, output_dir) action() return 0 def main(args): try: [input_file, output_dir] = args except ValueError: print_usage() return 1 transform(input_file, output_dir) def print_usage(): print('''\ usage: transform-file.py INPUT_FILE OUTPUT_DIRECTORY ''') if __name__ == '__main__': sys.exit(main(sys.argv[1:]))