template.py (3344B)
1 #!/usr/bin/env python3 2 3 import argparse 4 import datetime 5 import html 6 import html.parser 7 import os 8 import pathlib 9 10 11 argparser = argparse.ArgumentParser( 12 description='Templates html fragments into full html pages') 13 14 argparser.add_argument('src', type=argparse.FileType('r'), 15 help='The source html fragment') 16 argparser.add_argument('dst', type=argparse.FileType('w'), 17 help='The destination html file') 18 argparser.add_argument('tpl', type=argparse.FileType('r'), 19 help='The source html template') 20 argparser.add_argument('kwargs', nargs='*', 21 help='A list of custom \'key=val\' pairs to replace in the template') 22 23 24 def map_kwargs(kwargs): 25 return dict([arg.split('=', maxsplit=1) for arg in kwargs]) 26 27 28 def titleify(srcpath): 29 slug, ext = srcpath.rsplit('.', maxsplit=1) 30 31 seps = ['-', '_'] 32 for sep in seps: 33 slug = slug.replace(sep, ' ') 34 35 frags = [substr.capitalize() for substr in slug.split(' ')] 36 title = ' '.join(frags) 37 38 return title 39 40 41 def created(srcpath): 42 info = os.stat(srcpath) 43 return datetime.datetime.fromtimestamp(info.st_ctime) 44 45 46 def edited(srcpath): 47 info = os.stat(srcpath) 48 return datetime.datetime.fromtimestamp(info.st_mtime) 49 50 51 def fromisodate(isodate): 52 return datetime.datetime.fromisoformat(isodate) 53 54 55 TIMESTAMP = '%d %B %Y' 56 57 METADATA_SEPARATOR = '---' 58 59 60 def readfile(srcpath): 61 data = '' 62 with open(srcpath, 'r') as src: 63 data = src.read() 64 65 if METADATA_SEPARATOR in data: 66 return data.split(METADATA_SEPARATOR, maxsplit=1) 67 68 return '', data 69 70 71 def metadata(srcpath): 72 [metadata, *_] = readfile(srcpath) 73 74 keys = {} 75 for line in metadata.split('\n'): 76 line = line.strip() 77 if line: 78 [key, *val] = line.split(':', maxsplit=1) 79 keys[key] = ''.join(val).strip() 80 81 return keys 82 83 84 def content(srcpath): 85 [_, *contents] = readfile(srcpath) 86 87 return ' '.join(contents) 88 89 90 def article_keys(srcpath): 91 name = pathlib.Path(srcpath).name 92 93 keys = { 94 'title': titleify(name), 95 'created-iso': created(srcpath).isoformat(), 96 'edited-iso': edited(srcpath).isoformat(), 97 'content': content(srcpath), 98 } 99 100 keys |= metadata(srcpath) 101 102 keys |= { 103 'created-str': fromisodate(keys['created-iso']).strftime(TIMESTAMP), 104 'edited-str': fromisodate(keys['edited-iso']).strftime(TIMESTAMP), 105 } 106 107 # print(srcpath, keys) 108 109 return keys 110 111 112 def instantiate(tpl, kwargs): 113 splits = [] 114 115 cur = 0 116 end = len(tpl) 117 while cur < end: 118 key_start = tpl.find('%', cur) 119 key_end = tpl.find('%', key_start + 1) 120 121 if key_start == -1: 122 splits.append([cur, end, '']) 123 break 124 else: 125 splits.append([cur, key_start, tpl[key_start + 1:key_end]]) 126 127 cur = key_end + 1 128 129 out = '' 130 for [tpl_start, tpl_end, key] in splits: 131 out += tpl[tpl_start:tpl_end] 132 out += kwargs.get(key, '') 133 134 return out 135 136 137 if __name__ == '__main__': 138 args = argparser.parse_args() 139 140 template = '' 141 with args.tpl as tpl: 142 template = tpl.read() 143 144 with args.dst as dst: 145 keys = article_keys(args.src.name) 146 keys |= map_kwargs(args.kwargs) 147 148 dst.write(instantiate(template, keys)) 149