Files
blag/sg/sg.py
Bastian Venthur a7c93134b3 generate archive
2021-01-17 14:46:48 +01:00

177 lines
4.7 KiB
Python

#!/usr/bin/env python
"""Small static site generator.
"""
__author__ = "Bastian Venthur <venthur@debian.org>"
import argparse
import os
import shutil
import logging
from datetime import datetime
import markdown
from jinja2 import Environment, ChoiceLoader, FileSystemLoader, PackageLoader
import feedgenerator
logger = logging.getLogger(__name__)
logging.basicConfig(
level=logging.DEBUG,
format='%(asctime)s %(levelname)s %(name)s %(message)s',
)
def main(args=None):
args = parse_args(args)
args.func(args)
def parse_args(args):
"""Parse command line arguments.
Paramters
---------
args :
optional parameters, used for testing
Returns
-------
args
"""
parser = argparse.ArgumentParser()
commands = parser.add_subparsers(dest='command')
commands.required = True
build_parser = commands.add_parser('build')
build_parser.set_defaults(func=build)
build_parser.add_argument(
'-i', '--input-dir',
default='content',
help='Input directory (default: content)',
)
build_parser.add_argument(
'-o', '--output-dir',
default='build',
help='Ouptut directory (default: build)',
)
return parser.parse_args()
def build(args):
os.makedirs(f'{args.output_dir}', exist_ok=True)
convertibles = []
for root, dirnames, filenames in os.walk(args.input_dir):
for filename in filenames:
relpath = os.path.relpath(f'{root}/{filename}', start=args.input_dir)
abspath = os.path.abspath(f'{root}/{filename}')
# all non-markdown files are just copied over, the markdown
# files are converted to html
if abspath.endswith('.md'):
dstpath = os.path.abspath(f'{args.output_dir}/{relpath}')
dstpath = dstpath[:-3] + '.html'
convertibles.append((abspath, dstpath))
else:
shutil.copy(abspath, f'{args.output_dir}/{relpath}')
for dirname in dirnames:
# all directories are copied into the output directory
path = os.path.relpath(f'{root}/{dirname}', start=args.input_dir)
os.makedirs(f'{args.output_dir}/{path}', exist_ok=True)
convert_to_html(convertibles)
def convert_to_html(convertibles):
env = Environment(
loader=ChoiceLoader([
FileSystemLoader(['templates']),
PackageLoader('sg', 'templates'),
])
)
md = markdown.Markdown(
extensions=['meta', 'fenced_code', 'codehilite'],
output_format='html5',
)
pages = []
articles = []
for src, dst in convertibles:
logger.debug(f'Processing {src}')
with open(src, 'r') as fh:
body = fh.read()
md.reset()
content = md.convert(body)
meta = md.Meta
# convert markdown's weird format to str or list[str]
for key, value in meta.items():
value = '\n'.join(value).split(',')
value = [v.strip() for v in value]
if len(value) == 1:
value = value[0]
meta[key] = value
# convert known metadata
if 'date' in meta:
meta['date'] = datetime.fromisoformat(meta['date'])
context = dict(content=content)
context.update(meta)
# for now, treat all pages as articles
if not meta:
pages.append((dst, context))
#template = env.get_template('page.html')
else:
articles.append((dst, context))
#template = env.get_template('article.html')
template = env.get_template('article.html')
result = template.render(context)
with open(dst, 'w') as fh_dest:
fh_dest.write(result)
# generate feed
feed = feedgenerator.Atom1Feed(
link='https://venthur.de',
title='my title',
description='basti"s blag',
)
for dst, context in articles:
feed.add_item(
title=context['title'],
link=dst,
description=context['title'],
content=context['content'],
pubdate=context['date'],
)
with open('atom.xml', 'w') as fh:
feed.write(fh, encoding='utf8')
# generate archive
ctx = {}
archive = []
for dst, context in articles:
entry = context.copy()
entry['dst'] = dst
archive.append(entry)
archive = sorted(archive, key=lambda x: x['date'], reverse=True)
ctx['archive'] = archive
template = env.get_template('archive.html')
result = template.render(ctx)
with open('archive.html', 'w') as fh:
fh.write(result)
# generate tags
if __name__ == '__main__':
main()